Browse Source

add json validation functionality

Kolja Strohm 2 years ago
parent
commit
6790eac885
12 changed files with 2813 additions and 1312 deletions
  1. BIN
      Framework Tests/Framwork.dll
  2. 65 1
      Framework Tests/Json.cpp
  3. 1 0
      Framework.vcxproj
  4. 3 0
      Framework.vcxproj.filters
  5. 791 7
      JSON.cpp
  6. 595 0
      JSON.h
  7. 520 520
      UIMLView.cpp
  8. 17 0
      Writer.cpp
  9. 37 25
      Writer.h
  10. 504 486
      XML.cpp
  11. 177 171
      XML.h
  12. 103 102
      main.h

BIN
Framework Tests/Framwork.dll


+ 65 - 1
Framework Tests/Json.cpp

@@ -1,6 +1,8 @@
 #include "pch.h"
 #include "CppUnitTest.h"
 #include <Json.h>
+#define NO_MAIN
+#include <main.h>
 
 using namespace Microsoft::VisualStudio::CppUnitTestFramework;
 
@@ -124,7 +126,7 @@ namespace FrameworkTests
 			value2->release();
 		}
 
-		bool isEqual(Framework::JSON::JSONValue* a, Framework::JSON::JSONValue* b)
+		static bool isEqual(Framework::JSON::JSONValue* a, Framework::JSON::JSONValue* b)
 		{
 			if (a->getType() != b->getType()) return 0;
 			switch (a->getType())
@@ -282,4 +284,66 @@ namespace FrameworkTests
 			jArray->release();
 		}
 	};
+
+	TEST_CLASS(JSONValidatorTests)
+	{
+	private:
+		static OutputDebugStringBuf<char, std::char_traits<char>> charDebugOutput;
+		static std::streambuf* buf;
+
+	public:
+		TEST_CLASS_INITIALIZE(Init)
+		{
+			buf = std::cout.rdbuf();
+			std::cout.rdbuf(&charDebugOutput);
+		}
+		TEST_METHOD(ValidTest)
+		{
+			Framework::JSON::Validator::JSONValidator* validator = Framework::JSON::Validator::JSONValidator::buildForArray()->
+				addAcceptedObjectInArray()->
+				withRequiredNumber("x")->
+				whichIsLessThen(5)->
+				finishNumber()->
+				withRequiredBool("bla")->
+				whichIsOptional()->
+				withDefault(true)->
+				finishBool()->
+				finishObject()->finishArray();
+			Framework::JSON::JSONArray* jArray = Framework::JSON::Parser::getValue("[{\"x\": 4, \"bla\": false}]")->asArray();
+			Assert::IsTrue(validator->isValid(jArray), L"A valid json Array was marked as invalid by the validator");
+			validator->release();
+		}
+
+		TEST_METHOD(ComplexTest)
+		{
+			Framework::JSON::Validator::JSONValidator* validator = Framework::JSON::Validator::JSONValidator::buildForArray()->typeSpecifiedByAttribute("type")->addAcceptedObjectInArray()->withRequiredString("type")->withExactMatch("shaped")->finishString()->withRequiredString("group")->finishString()->withRequiredNumber("width")->whichIsGreaterThen(0)->finishNumber()->withRequiredNumber("height")->whichIsGreaterThen(0)->finishNumber()->withRequiredArray("inputs")->addAcceptedObjectInArray()->withRequiredNumber("x")->whichIsGreaterOrEqual(0)->finishNumber()->withRequiredNumber("y")->whichIsGreaterOrEqual(0)->finishNumber()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->finishObject()->finishArray()->withRequiredObject("output")->withRequiredString("itemType")->finishString()->finishObject()->withRequiredNumber("outputCount")->whichIsGreaterThen(0)->finishNumber()->finishObject()->addAcceptedObjectInArray()->withRequiredString("type")->withExactMatch("unordered")->finishString()->withRequiredString("group")->finishString()->withRequiredArray("inputs")->addAcceptedObjectInArray()->withRequiredNumber("count")->whichIsGreaterThen(0)->finishNumber()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->finishObject()->finishArray()->withRequiredArray("output")->addAcceptedObjectInArray()->withRequiredObject("filter")->withRequiredString("itemType")->finishString()->finishObject()->withRequiredNumber("count")->whichIsGreaterThen(0)->finishNumber()->finishObject()->finishArray()->finishObject()->finishArray();
+			std::cout << validator->zConstraints()->toString().getText() << "\n";
+			Framework::JSON::JSONValue* value = Framework::JSON::Parser::getValue("[{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": -1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1},{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": 1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1}]");
+			std::cout << value->toString().getText() << "\n";
+			Framework::JSON::Validator::JSONValidationResult* result = validator->validate(value);
+			result->printInvalidInfo();
+			Assert::IsTrue(!result->isValid(), L"Invalid Json was marked as valid");
+			Framework::JSON::JSONValue* validValue = result->getValidPart();
+			result->release();
+			Framework::JSON::JSONValue* expected = Framework::JSON::Parser::getValue("[{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1},{\"type\": \"shaped\",\"group\": \"inventory\",\"width\": 1,\"height\": 2,\"inputs\": [{\"x\": 0,\"y\": 0,\"filter\": {\"itemType\": \"Cobble\"}},{\"x\": 0,\"y\": 1,\"filter\": {\"itemType\": \"Cobble\"}}],\"output\": {\"itemType\": \"StoneTool\"},\"outputCount\": 1}]");
+			Assert::IsTrue(JSONParserTests::isEqual(validValue, expected), L"getValidPart of invalid validation result does not match the expected valid part");
+			result = validator->validate(validValue);
+			Assert::IsTrue(result->isValid(), L"Re validation of a value returned by getValidPart on a validation result should never return an invalid validation result");
+			value->release();
+			value = result->getValidPart();
+			Assert::IsTrue(JSONParserTests::isEqual(validValue, value), L"getValidPart of a valid validation result should return the validated value");
+			value->release();
+			validValue->release();
+			expected->release();
+			validator->release();
+		}
+
+		TEST_CLASS_CLEANUP(Cleanup)
+		{
+			std::cout.rdbuf(buf);
+		}
+	};
+
+	OutputDebugStringBuf<char, std::char_traits<char>> JSONValidatorTests::charDebugOutput;
+	std::streambuf* JSONValidatorTests::buf;
 }

+ 1 - 0
Framework.vcxproj

@@ -350,6 +350,7 @@ copy "x64\Release\Framework.dll" "..\..\Spiele Platform\SMP\Fertig\x64\framework
     <ClCompile Include="UIMLView.cpp" />
     <ClCompile Include="Welt2D.cpp" />
     <ClCompile Include="Welt3D.cpp" />
+    <ClCompile Include="Writer.cpp" />
     <ClCompile Include="XML.cpp" />
     <ClCompile Include="Zeichnung3D.cpp" />
     <ClCompile Include="Zeichnung.cpp" />

+ 3 - 0
Framework.vcxproj.filters

@@ -599,6 +599,9 @@
     <ClCompile Include="Model3DCollection.h">
       <Filter>Headerdateien\Framework\Grafik\3D</Filter>
     </ClCompile>
+    <ClCompile Include="Writer.cpp">
+      <Filter>Quelldateien\Framework\IO</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <FxCompile Include="DX12VertexShader.hlsl">

+ 791 - 7
JSON.cpp

@@ -29,23 +29,33 @@ Text JSONValue::toString() const
 	return Text("null");
 }
 
-JSONBool* JSONValue::asBool() const {
+JSONValue* JSONValue::clone() const
+{
+	return new JSONValue();
+}
+
+JSONBool* JSONValue::asBool() const
+{
 	return (JSONBool*)this;
 }
 
-JSONNumber* JSONValue::asNumber() const {
+JSONNumber* JSONValue::asNumber() const
+{
 	return (JSONNumber*)this;
 }
 
-JSONString* JSONValue::asString() const {
+JSONString* JSONValue::asString() const
+{
 	return (JSONString*)this;
 }
 
-JSONArray* JSONValue::asArray() const {
+JSONArray* JSONValue::asArray() const
+{
 	return (JSONArray*)this;
 }
 
-JSONObject* JSONValue::asObject() const {
+JSONObject* JSONValue::asObject() const
+{
 	return (JSONObject*)this;
 }
 
@@ -69,6 +79,11 @@ Text JSONBool::toString() const
 		return Text("false");
 }
 
+JSONValue* JSONBool::clone() const
+{
+	return new JSONBool(b);
+}
+
 
 JSONNumber::JSONNumber(double num)
 	: JSONValue(JSONType::NUMBER)
@@ -86,11 +101,17 @@ Text JSONNumber::toString() const
 	return Text(number);
 }
 
+JSONValue* JSONNumber::clone() const
+{
+	return new JSONNumber(number);
+}
+
 
 JSONString::JSONString(Text string)
 	: JSONValue(JSONType::STRING)
 {
 	this->string = string;
+	string.ersetzen("\\\"", "\"");
 }
 
 Text JSONString::getString() const
@@ -100,7 +121,14 @@ Text JSONString::getString() const
 
 Text JSONString::toString() const
 {
-	return Text(Text("\"") += string.getText()) += "\"";
+	Text esc = string;
+	esc.ersetzen("\"", "\\\"");
+	return Text(Text("\"") += esc.getText()) += "\"";
+}
+
+JSONValue* JSONString::clone() const
+{
+	return new JSONString(string);
 }
 
 
@@ -153,11 +181,26 @@ void JSONArray::addValue(JSONValue* value)
 	array->add(value);
 }
 
+void JSONArray::setValue(int i, JSONValue* value)
+{
+	array->set(value, i);
+}
+
+void JSONArray::removeValue(int i)
+{
+	array->remove(i);
+}
+
 JSONValue* JSONArray::getValue(int i) const
 {
 	return array->get(i);
 }
 
+JSONValue* JSONArray::zValue(int i) const
+{
+	return array->z(i);
+}
+
 int JSONArray::getLength() const
 {
 	return array->getEintragAnzahl();
@@ -168,6 +211,16 @@ bool JSONArray::isValueOfType(int i, JSONType type) const
 	return i >= 0 && i < array->getEintragAnzahl() && array->z(i)->getType() == type;
 }
 
+Iterator< JSONValue* > JSONArray::begin() const
+{
+	return array->begin();
+}
+
+Iterator< JSONValue* > JSONArray::end() const
+{
+	return array->end();
+}
+
 Text JSONArray::toString() const
 {
 	Text str = "[";
@@ -181,6 +234,11 @@ Text JSONArray::toString() const
 	return str;
 }
 
+JSONValue* JSONArray::clone() const
+{
+	return new JSONArray(toString());
+}
+
 
 JSONObject::JSONObject()
 	: JSONValue(JSONType::OBJECT)
@@ -281,7 +339,17 @@ JSONValue* JSONObject::getValue(Text field)
 		if (fields->get(i).istGleich(field))
 			return values->get(i);
 	}
-	return new JSONValue();
+	return 0;
+}
+
+JSONValue* JSONObject::zValue(Text field)
+{
+	for (int i = 0; i < fields->getEintragAnzahl(); i++)
+	{
+		if (fields->get(i).istGleich(field))
+			return values->z(i);
+	}
+	return 0;
 }
 
 Iterator< Text > JSONObject::getFields()
@@ -326,6 +394,11 @@ Text JSONObject::toString() const
 	return str;
 }
 
+JSONValue* JSONObject::clone() const
+{
+	return new JSONObject(toString());
+}
+
 JSONValue* JSON::loadJSONFromFile(Text path)
 {
 	Datei d;
@@ -558,4 +631,715 @@ int Parser::findValueEndInObject(const char* str)
 		}
 	}
 	return i;
+}
+
+
+using namespace Validator;
+
+
+JSONValidationResult::JSONValidationResult()
+	: ReferenceCounter()
+{}
+
+JSONValidationResult::~JSONValidationResult() {}
+
+
+JSONTypeMissmatch::JSONTypeMissmatch(Text path, JSONValue* foundValue, XML::Element* expected, JSONValidationResult* reason)
+	: JSONValidationResult()
+{
+	this->path = path;
+	this->foundValue = foundValue;
+	this->expected = expected;
+	this->reason = reason;
+}
+
+JSONTypeMissmatch::~JSONTypeMissmatch()
+{
+	foundValue->release();
+	expected->release();
+	if (reason)
+		reason->release();
+}
+
+bool JSONTypeMissmatch::isValid() const
+{
+	return 0;
+}
+
+void JSONTypeMissmatch::printInvalidInfo(int indent) const
+{
+	Text ind = "";
+	ind.fillText(' ', indent);
+	std::cout << ind.getText() << "Type missmatch at path '" << path.getText() << "'. JSON Value\n" << ind.getText() << foundValue->toString().getText() << "\n" << ind.getText() << "does not match type\n" << ind.getText() << expected->toString().getText() << "\n";
+	if (reason)
+	{
+		std::cout << ind.getText() << "Reason for type mismatch:\n";
+		reason->printInvalidInfo(indent + 4);
+	}
+}
+
+JSONValue* JSONTypeMissmatch::getValidPart() const
+{
+	if (reason)
+	{
+		JSONValue* valid = reason->getValidPart();
+		Text* p = reason->getPath().getTeilText(path.getLength());
+		if (foundValue->getType() == JSONType::ARRAY)
+		{
+			if (p->hatAt(0, "[") && p->hatAt(p->getLength() - 1, "]"))
+			{
+				Text* it = p->getTeilText(1, p->getLength() - 1);
+				int i = *it;
+				it->release();
+				if (i >= 0 && foundValue->asArray()->getLength() > i)
+				{
+					JSONValue* tmp = foundValue->clone();
+					if (valid)
+						tmp->asArray()->setValue(i, valid);
+					else
+						tmp->asArray()->removeValue(i);
+					JSONValidationResult* res = JSONValidator(dynamic_cast<XML::Element*>(expected->getThis())).validate(tmp);
+					if (res->isValid())
+					{
+						res->release();
+						p->release();
+						return tmp;
+					}
+					else if (res->isDifferent(this, path) || !valid)
+					{
+						p->release();
+						tmp->release();
+						JSONValue* result = res->getValidPart();
+						res->release();
+						return result;
+					}
+					tmp->release();
+					res->release();
+				}
+			}
+		}
+		else if (foundValue->getType() == JSONType::OBJECT)
+		{
+			if (p->hatAt(0, "."))
+			{
+				Text* at = p->getTeilText(1);
+				Text attr = *at;
+				at->release();
+				if (foundValue->asObject()->hasValue(attr))
+				{
+					JSONValue* tmp = foundValue->clone();
+					tmp->asObject()->removeValue(attr);
+					if (valid)
+						tmp->asObject()->addValue(attr, valid);
+					JSONValidationResult* res = JSONValidator(dynamic_cast<XML::Element*>(expected->getThis())).validate(tmp);
+					if (res->isValid())
+					{
+						res->release();
+						p->release();
+						return tmp;
+					}
+					else if (res->isDifferent(this, path) || !valid)
+					{
+						p->release();
+						tmp->release();
+						JSONValue* result = res->getValidPart();
+						res->release();
+						return result;
+					}
+					tmp->release();
+					res->release();
+				}
+			}
+		}
+		p->release();
+		if (valid)
+			valid->release();
+	}
+	if (expected->hasAttribute("default"))
+	{
+		JSONValue* def = Parser::getValue(expected->getAttributeValue("default"));
+		JSONValidationResult* res = JSONValidator(dynamic_cast<XML::Element*>(expected->getThis())).validate(def);
+		if (res->isValid())
+		{
+			res->release();
+			return def;
+		}
+		else if (res->isDifferent(this, path))
+		{
+			def->release();
+			JSONValue* result = res->getValidPart();
+			res->release();
+			return result;
+		}
+		def->release();
+	}
+	return 0;
+}
+
+Text JSONTypeMissmatch::getPath() const
+{
+	return path;
+}
+
+bool JSONTypeMissmatch::isDifferent(const JSONValidationResult* zResult, Text additionalPath) const
+{
+	const JSONTypeMissmatch* casted = dynamic_cast<const JSONTypeMissmatch*>(zResult);
+	if (casted == 0)
+		return 1;
+	if (!casted->getPath().istGleich(additionalPath + path))
+		return 1;
+	return reason->isDifferent(casted->reason, path);
+}
+
+
+JSONUnknownValue::JSONUnknownValue(Text path, JSONValue* foundValue)
+	: JSONValidationResult()
+{
+	this->path = path;
+	this->foundValue = foundValue;
+}
+
+JSONUnknownValue::~JSONUnknownValue()
+{
+	foundValue->release();
+}
+
+bool JSONUnknownValue::isValid() const
+{
+	return 0;
+}
+
+void JSONUnknownValue::printInvalidInfo(int indent) const
+{
+	Text ind = "";
+	ind.fillText(' ', indent);
+	std::cout << ind.getText() << "Unknown Value at '" << path.getText() << "'. Value found:\n" << foundValue->toString().getText() << "\n";
+}
+
+JSONValue* JSONUnknownValue::getValidPart() const
+{
+	return 0;
+}
+
+Text JSONUnknownValue::getPath() const
+{
+	return path;
+}
+
+bool JSONUnknownValue::isDifferent(const JSONValidationResult* zResult, Text additionalPath) const
+{
+	const JSONUnknownValue* casted = dynamic_cast<const JSONUnknownValue*>(zResult);
+	if (casted == 0)
+		return 1;
+	if (!casted->getPath().istGleich(additionalPath + path))
+		return 1;
+	return 0;
+}
+
+
+JSONMissingValue::JSONMissingValue(Text path, XML::Element* expected)
+	: JSONValidationResult()
+{
+	this->path = path;
+	this->expected = expected;
+}
+
+JSONMissingValue::~JSONMissingValue()
+{
+	expected->release();
+}
+
+bool JSONMissingValue::isValid() const
+{
+	return 0;
+}
+
+void JSONMissingValue::printInvalidInfo(int indent) const
+{
+	Text ind = "";
+	ind.fillText(' ', indent);
+	std::cout << ind.getText() << "Missing Value at '" << path.getText() << "'. Expected type:\n" << expected->toString().getText() << "\n";
+}
+
+JSONValue* JSONMissingValue::getValidPart() const
+{
+	if (expected->hasAttribute("default"))
+	{
+		JSONValue* def = Parser::getValue(expected->getAttributeValue("default"));
+		JSONValidationResult* res = JSONValidator(dynamic_cast<XML::Element*>(expected->getThis())).validate(def);
+		if (res->isValid())
+		{
+			res->release();
+			return def;
+		}
+		else if (res->isDifferent(this, path))
+		{
+			def->release();
+			JSONValue* result = res->getValidPart();
+			res->release();
+			return result;
+		}
+		def->release();
+	}
+	return 0;
+}
+
+Text JSONMissingValue::getPath() const
+{
+	return path;
+}
+
+bool JSONMissingValue::isDifferent(const JSONValidationResult* zResult, Text additionalPath) const
+{
+	const JSONMissingValue* casted = dynamic_cast<const JSONMissingValue*>(zResult);
+	if (casted == 0)
+		return 1;
+	if (!casted->getPath().istGleich(additionalPath + path))
+		return 1;
+	return 0;
+}
+
+
+JSONMissingOneOf::JSONMissingOneOf(Text path, XML::Editor expected)
+	: JSONValidationResult()
+{
+	this->path = path;
+	for (XML::Element* e : expected)
+		this->expected.add(dynamic_cast<XML::Element*>(e->getThis()));
+}
+
+JSONMissingOneOf::~JSONMissingOneOf()
+{}
+
+bool JSONMissingOneOf::isValid() const
+{
+	return 0;
+}
+
+void JSONMissingOneOf::printInvalidInfo(int indent) const
+{
+	Text ind = "";
+	ind.fillText(' ', indent);
+	std::cout << ind.getText() << "Missing Value at '" << path.getText() << "'. The value should have one of the following types:\n";
+	ind += "    ";
+	for (XML::Element* e : expected)
+	{
+		std::cout << ind.getText() << e->toString().getText() << "\n";
+	}
+}
+
+JSONValue* JSONMissingOneOf::getValidPart() const
+{
+	// multiple possibilities are undecidable
+	return 0;
+}
+
+Text JSONMissingOneOf::getPath() const
+{
+	return path;
+}
+
+bool JSONMissingOneOf::isDifferent(const JSONValidationResult* zResult, Text additionalPath) const
+{
+	const JSONMissingOneOf* casted = dynamic_cast<const JSONMissingOneOf*>(zResult);
+	if (casted == 0)
+		return 1;
+	if (!casted->getPath().istGleich(additionalPath + path))
+		return 1;
+	return 0;
+}
+
+
+JSONNoTypeMatching::JSONNoTypeMatching(Text path, JSONValue* foundValue, RCArray<XML::Element>& expected, RCArray<JSONValidationResult>& reasons)
+	: JSONValidationResult()
+{
+	this->path = path;
+	this->foundValue = foundValue;
+	this->expected = expected;
+	this->reasons = reasons;
+}
+
+JSONNoTypeMatching::~JSONNoTypeMatching()
+{
+	foundValue->release();
+}
+
+bool JSONNoTypeMatching::isValid() const
+{
+	return 0;
+}
+
+void JSONNoTypeMatching::printInvalidInfo(int indent) const
+{
+	Text ind = "";
+	ind.fillText(' ', indent);
+	std::cout << ind.getText() << "Found Value at '" << path.getText() << "' did not match any of the given possible types:\n";
+	Text ind2 = ind + "    ";
+	for (XML::Element* element : expected)
+	{
+		std::cout << ind2.getText() << element->toString().getText() << "\n";
+	}
+
+	std::cout << ind.getText() << "Reasons:\n";
+	for (JSONValidationResult* reason : reasons)
+	{
+		reason->printInvalidInfo(indent + 4);
+	}
+}
+
+JSONValue* JSONNoTypeMatching::getValidPart() const
+{
+	// multiple possibilities are undecidable
+	return 0;
+}
+
+Text JSONNoTypeMatching::getPath() const
+{
+	return path;
+}
+
+bool JSONNoTypeMatching::isDifferent(const JSONValidationResult* zResult, Text additionalPath) const
+{
+	const JSONNoTypeMatching* casted = dynamic_cast<const JSONNoTypeMatching*>(zResult);
+	if (casted == 0)
+		return 1;
+	if (!casted->getPath().istGleich(additionalPath + path))
+		return 1;
+	for (int i = 0; i < reasons.getEintragAnzahl(); i++)
+	{
+		if (reasons.z(i)->isDifferent(casted->reasons.z(i), additionalPath))
+			return 1;
+	}
+	return 0;
+}
+
+
+JSONValidValue::JSONValidValue(Text path, JSONValue* value)
+	: JSONValidationResult()
+{
+	this->path = path;
+	this->value = value;
+}
+
+JSONValidValue::~JSONValidValue()
+{
+	value->release();
+}
+
+bool JSONValidValue::isValid() const
+{
+	return 1;
+}
+
+void JSONValidValue::printInvalidInfo(int indent) const
+{}
+
+JSONValue* JSONValidValue::getValidPart() const
+{
+	return value->clone();
+}
+
+Text JSONValidValue::getPath() const
+{
+	return path;
+}
+
+bool JSONValidValue::isDifferent(const JSONValidationResult* zResult, Text additionalPath) const
+{
+	const JSONValidValue* casted = dynamic_cast<const JSONValidValue*>(zResult);
+	if (casted == 0)
+		return 1;
+	if (!casted->getPath().istGleich(additionalPath + path))
+		return 1;
+	return 0;
+}
+
+
+JSONValidator::JSONValidator(XML::Element* constraints)
+	: ReferenceCounter(),
+	constraints(constraints)
+{}
+
+JSONValidator::~JSONValidator()
+{
+	constraints->release();
+}
+
+JSONValidationResult* JSONValidator::validate(JSONValue* zValue) const
+{
+	return validate(zValue, constraints, "");
+}
+
+bool JSONValidator::isValid(JSONValue* zValue) const
+{
+	JSONValidationResult* res = validate(zValue);
+	if (res->isValid())
+	{
+		res->release();
+		return 1;
+	}
+	res->release();
+	return 0;
+}
+
+JSONValue* JSONValidator::getValidParts(JSONValue* zValue) const
+{
+	JSONValidationResult* res = validate(zValue);
+	if (res->isValid())
+	{
+		res->release();
+		return zValue->clone();
+	}
+	JSONValue* valid = res->getValidPart();
+	res->release();
+	return valid;
+}
+
+XML::Element* JSONValidator::zConstraints()
+{
+	return constraints;
+}
+
+JSONValidationResult* JSONValidator::validate(JSONValue* zValue, XML::Element* zConstraints, Text path) const
+{
+	switch (zValue->getType())
+	{
+	case JSONType::NULL_:
+		if (!zConstraints->hasAttribute("nullable") || !zConstraints->getAttributeValue("nullable").istGleich("true"))
+		{
+			return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+		}
+		break;
+	case JSONType::BOOLEAN:
+		if (!zConstraints->getName().istGleich("bool"))
+		{
+			return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+		}
+		else if (zConstraints->hasAttribute("equals"))
+		{
+			if (!zConstraints->getAttributeValue("equals").istGleich("true") == !zValue->asBool()->getBool())
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+		}
+		break;
+	case JSONType::NUMBER:
+		if (!zConstraints->getName().istGleich("number"))
+		{
+			return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+		}
+		else
+		{
+			if (zConstraints->hasAttribute("equals") && (double)zConstraints->getAttributeValue("equals") != zValue->asNumber()->getNumber())
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+			else if (zConstraints->hasAttribute("lessOrEqual") && zValue->asNumber()->getNumber() > (double)zConstraints->getAttributeValue("lessOrEqual"))
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+			else if (zConstraints->hasAttribute("greaterOrEqual") && zValue->asNumber()->getNumber() < (double)zConstraints->getAttributeValue("greaterOrEqual"))
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+			else if (zConstraints->hasAttribute("less") && zValue->asNumber()->getNumber() >= (double)zConstraints->getAttributeValue("less"))
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+			else if (zConstraints->hasAttribute("greater") && zValue->asNumber()->getNumber() <= (double)zConstraints->getAttributeValue("greater"))
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+		}
+		break;
+	case JSONType::STRING:
+		if (!zConstraints->getName().istGleich("string"))
+		{
+			return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+		}
+		else
+		{
+			if (zConstraints->hasAttribute("equals") && !zConstraints->getAttributeValue("equals").istGleich(zValue->asString()->getString()))
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+			else if (zConstraints->hasAttribute("contains") && zValue->asString()->getString().hat(zConstraints->getAttributeValue("contains")))
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+			else if (zConstraints->hasAttribute("startsWith") && zValue->asString()->getString().positionVon(zConstraints->getAttributeValue("startsWith")) == 0)
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+			else if (zConstraints->hasAttribute("endsWith") && zValue->asString()->getString().positionVon(zConstraints->getAttributeValue("endsWith")) == zValue->asString()->getString().getLength() - zConstraints->getAttributeValue("endsWith").getLength())
+			{
+				return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+			}
+		}
+		break;
+	case JSONType::ARRAY:
+		if (!zConstraints->getName().istGleich("array"))
+		{
+			return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+		}
+		else
+		{
+			bool valid = 1;
+			int index = 0;
+			for (JSON::JSONValue* value : *zValue->asArray())
+			{
+				Text p = path;
+				p += "[";
+				p += index;
+				p += "]";
+				JSONValidationResult* res = validateMultipleTypes(value, zConstraints, p);
+				if (!res->isValid())
+				{
+					return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), res);
+				}
+				res->release();
+				index++;
+			}
+		}
+		break;
+	case JSONType::OBJECT:
+		if (!zConstraints->getName().istGleich("object"))
+		{
+			return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), 0);
+		}
+		else
+		{
+			bool valid = 1;
+			JSON::JSONObject* obj = zValue->asObject();
+			for (auto i = obj->getFields(); i; i++)
+			{
+				Text p = path;
+				p += ".";
+				p += i.val();
+				if (!zConstraints->selectChildsByAttribute("name", i.val()).exists())
+				{
+					return new JSONUnknownValue(p, zValue->asObject()->getValue(i.val()));
+				}
+				else
+				{
+					bool isValueValid = 0;
+					JSONValidationResult* res = validateMultipleTypes(zValue->asObject()->zValue(i.val()), zConstraints->selectChildsByAttribute("name", i.val()).begin().val(), p);
+					if (!res->isValid())
+					{
+						return new JSONTypeMissmatch(path, dynamic_cast<JSONValue*>(zValue->getThis()), dynamic_cast<XML::Element*>(zConstraints->getThis()), res);
+					}
+					res->release();
+				}
+			}
+			for (XML::Element* constraint : zConstraints->selectChildren())
+			{
+				if (!zValue->asObject()->hasValue(constraint->getAttributeValue("name")))
+				{
+					Text p = path;
+					p += ".";
+					p += constraint->getAttributeValue("name");
+					if (constraint->getChildCount() != 1)
+						return new JSONMissingOneOf(p, constraint->selectChildren());
+					return new JSONMissingValue(path, dynamic_cast<XML::Element*>(constraint->selectChildren().begin().val()->getThis()));
+				}
+			}
+		}
+		break;
+	}
+	return new JSONValidValue(path, dynamic_cast<JSONValue*>(zValue->getThis()));
+}
+
+JSONValidationResult* JSONValidator::validateMultipleTypes(JSONValue* zChildValue, XML::Element* zPossibleChildConstraints, Text childPath) const
+{
+	if (zPossibleChildConstraints->getChildCount() == 1)
+		return validate(zChildValue, zPossibleChildConstraints->selectChildren().begin().val(), childPath); // only one type is possible
+	bool hasTypeAttr = 0;
+	RCArray<XML::Element> possibleConstraints;
+	if (zPossibleChildConstraints->hasAttribute("typeSpecifiedBy"))
+	{ // try to find the correct constraints based on the type attribute
+		hasTypeAttr = 1;
+		Text typeAttr = zPossibleChildConstraints->getAttributeValue("typeSpecifiedBy");
+		if (zChildValue->getType() == JSONType::OBJECT)
+		{
+			if (zChildValue->asObject()->hasValue(typeAttr))
+			{
+				JSONValue* typeV = zChildValue->asObject()->zValue(typeAttr);
+				for (XML::Element* constraint : zPossibleChildConstraints->selectChildsByName("object").whereChildWithAttributeExists("name", typeAttr))
+				{
+					XML::Element* typeAttrContraints = constraint->selectChildsByAttribute("name", typeAttr).begin().val();
+					JSONValidationResult* res = validateMultipleTypes(typeV, typeAttrContraints, childPath + "." + typeAttr);
+					if (res->isValid())
+						possibleConstraints.add(dynamic_cast<XML::Element*>(constraint->getThis()));
+					res->release();
+				}
+			}
+		}
+	}
+	if (hasTypeAttr && possibleConstraints.getEintragAnzahl() == 1)
+		return validate(zChildValue, possibleConstraints.begin().val(), childPath); // if the type is clear
+	else if (hasTypeAttr && possibleConstraints.getEintragAnzahl() > 0)
+	{ // more then one type is possible
+		RCArray< JSONValidationResult> invalidResults;
+		for (XML::Element* constraint : possibleConstraints)
+		{
+			JSONValidationResult* res = validate(zChildValue, constraint, childPath);
+			invalidResults.add(res);
+			if (res->isValid())
+				return new JSONValidValue(childPath, dynamic_cast<JSONValue*>(zChildValue->getThis()));
+		}
+		return new JSONNoTypeMatching(childPath, dynamic_cast<JSONValue*>(zChildValue->getThis()), possibleConstraints, invalidResults);
+	}
+	// try all types
+	possibleConstraints.leeren();
+	RCArray< JSONValidationResult> invalidResults;
+	for (XML::Element* constraint : zPossibleChildConstraints->selectChildren())
+	{
+		JSONValidationResult* res = validate(zChildValue, constraint, childPath);
+		invalidResults.add(res);
+		if (res->isValid())
+			return new JSONValidValue(childPath, dynamic_cast<JSONValue*>(zChildValue->getThis()));
+		possibleConstraints.add(dynamic_cast<XML::Element*>(constraint->getThis()));
+	}
+	return new JSONNoTypeMatching(childPath, dynamic_cast<JSONValue*>(zChildValue->getThis()), possibleConstraints, invalidResults);
+}
+
+
+StringValidationBuilder<JSONValidator>* JSONValidator::buildForString()
+{
+	return new StringValidationBuilder<JSONValidator>([](XML::Element& e)
+		{
+			return new JSONValidator(e.dublicate());
+		});
+}
+
+NumberValidationBuilder<JSONValidator>* JSONValidator::buildForNumber()
+{
+	return new NumberValidationBuilder<JSONValidator>([](XML::Element& e)
+		{
+			return new JSONValidator(e.dublicate());
+		});
+}
+
+BoolValidationBuilder<JSONValidator>* JSONValidator::buildForBool()
+{
+	return new BoolValidationBuilder<JSONValidator>([](XML::Element& e)
+		{
+			return new JSONValidator(e.dublicate());
+		});
+}
+
+ObjectValidationBuilder<JSONValidator>* JSONValidator::buildForObject()
+{
+	return new ObjectValidationBuilder<JSONValidator>([](XML::Element& e)
+		{
+			return new JSONValidator(e.dublicate());
+		});
+}
+
+ArrayValidationBuilder<JSONValidator>* JSONValidator::buildForArray()
+{
+	return new ArrayValidationBuilder<JSONValidator>([](XML::Element& e)
+		{
+			return new JSONValidator(e.dublicate());
+		});
 }

+ 595 - 0
JSON.h

@@ -3,6 +3,8 @@
 #include "Text.h"
 #include "Array.h"
 #include "ReferenceCounter.h"
+#include "XML.h"
+#include "Writer.h"
 #include <functional>
 
 namespace Framework
@@ -38,6 +40,7 @@ namespace Framework
 			__declspec(dllexport) virtual ~JSONValue();
 			__declspec(dllexport) JSONType getType() const;
 			__declspec(dllexport) virtual Text toString() const;
+			__declspec(dllexport) virtual JSONValue* clone() const;
 			__declspec(dllexport) JSONBool* asBool() const;
 			__declspec(dllexport) JSONNumber* asNumber() const;
 			__declspec(dllexport) JSONString* asString() const;
@@ -55,6 +58,7 @@ namespace Framework
 
 			__declspec(dllexport) bool getBool() const;
 			__declspec(dllexport) Text toString() const override;
+			__declspec(dllexport) JSONValue* clone() const override;
 		};
 
 		class JSONNumber : public JSONValue
@@ -67,6 +71,7 @@ namespace Framework
 
 			__declspec(dllexport) double getNumber() const;
 			__declspec(dllexport) Text toString() const override;
+			__declspec(dllexport) JSONValue* clone() const override;
 		};
 
 		class JSONString : public JSONValue
@@ -79,6 +84,7 @@ namespace Framework
 
 			__declspec(dllexport) Text getString() const;
 			__declspec(dllexport) Text toString() const override;
+			__declspec(dllexport) JSONValue* clone() const override;
 		};
 
 		class JSONArray : public JSONValue
@@ -95,10 +101,18 @@ namespace Framework
 			__declspec(dllexport) JSONArray& operator=(const JSONArray& arr);
 
 			__declspec(dllexport) void addValue(JSONValue* value);
+			__declspec(dllexport) void setValue(int i, JSONValue* value);
+			__declspec(dllexport) void removeValue(int i);
 			__declspec(dllexport) JSONValue* getValue(int i) const;
+			__declspec(dllexport) JSONValue* zValue(int i) const;
 			__declspec(dllexport) int getLength() const;
 			__declspec(dllexport) bool isValueOfType(int i, JSONType type) const;
 
+			//! Gibt einen Iterator zurück.
+			//! Mit ++ kann durch die Liste iteriert werden
+			__declspec(dllexport) Iterator< JSONValue* > begin() const;
+			__declspec(dllexport) Iterator< JSONValue* > end() const;
+
 			template<class T>
 			RCArray<T>* toRCArray(std::function<T* (JSONValue&)> map) const
 			{
@@ -140,6 +154,7 @@ namespace Framework
 			}
 
 			__declspec(dllexport) Text toString() const override;
+			__declspec(dllexport) JSONValue* clone() const override;
 
 
 			template<class T>
@@ -183,6 +198,7 @@ namespace Framework
 			__declspec(dllexport) bool removeValue(Text field);
 			__declspec(dllexport) bool hasValue(Text field);
 			__declspec(dllexport) JSONValue* getValue(Text field);
+			__declspec(dllexport) JSONValue* zValue(Text field);
 			__declspec(dllexport) Iterator< Text > getFields();
 			__declspec(dllexport) Iterator< JSONValue* > getValues();
 			__declspec(dllexport) int getFieldCount() const;
@@ -203,6 +219,7 @@ namespace Framework
 			}
 
 			__declspec(dllexport) Text toString() const override;
+			__declspec(dllexport) JSONValue* clone() const override;
 		};
 
 		__declspec(dllexport) JSONValue* loadJSONFromFile(Text path);
@@ -215,5 +232,583 @@ namespace Framework
 			__declspec(dllexport) int findFieldEndInObject(const char* str);
 			__declspec(dllexport) int findValueEndInObject(const char* str);
 		};
+
+		namespace Validator
+		{
+			template<typename T>
+			class StringValidationBuilder
+			{
+			private:
+				XML::Element element;
+				std::function<T* (XML::Element& element)> builder;
+
+			public:
+				StringValidationBuilder(std::function<T* (XML::Element& element)> builder)
+					: element("<string/>"),
+					builder(builder)
+				{}
+
+				StringValidationBuilder<T>* withExactMatch(Text value)
+				{
+					element.setAttribute("equals", value);
+					return this;
+				}
+
+				StringValidationBuilder<T>* whichContainsMatch(Text value)
+				{
+					element.setAttribute("contains", value);
+					return this;
+				}
+
+				StringValidationBuilder<T>* whichStartsWithMatch(Text value)
+				{
+					element.setAttribute("startsWith", value);
+					return this;
+				}
+
+				StringValidationBuilder<T>* whichEndsWithMatch(Text value)
+				{
+					element.setAttribute("endsWith", value);
+					return this;
+				}
+
+				StringValidationBuilder<T>* withDefault(Text value)
+				{
+					element.setAttribute("default", JSONString(value).toString());
+					return this;
+				}
+
+				StringValidationBuilder<T>* withDefaultNull()
+				{
+					element.setAttribute("default", "null");
+					return this;
+				}
+
+				StringValidationBuilder<T>* whichCanBeNull()
+				{
+					element.setAttribute("nullable", "true");
+					return this;
+				}
+
+				StringValidationBuilder<T>* whichIsOptional()
+				{
+					element.setAttribute("optional", "true");
+					return this;
+				}
+
+				T* finishString()
+				{
+					T* result = builder(element);
+					delete this;
+					return result;
+				}
+			};
+
+			template<typename T>
+			class NumberValidationBuilder
+			{
+			private:
+				XML::Element element;
+				std::function<T* (XML::Element& element)> builder;
+
+			public:
+				NumberValidationBuilder(std::function<T* (XML::Element& element)> builder)
+					: element("<number/>"),
+					builder(builder)
+				{}
+
+				NumberValidationBuilder<T>* whichIs(double value)
+				{
+					element.setAttribute("equals", Text(value));
+					return this;
+				}
+
+				NumberValidationBuilder<T>* whichIsLessOrEqual(double value)
+				{
+					element.setAttribute("lessOrEqual", Text(value));
+					return this;
+				}
+
+				NumberValidationBuilder<T>* whichIsGreaterOrEqual(double value)
+				{
+					element.setAttribute("greaterOrEqual", Text(value));
+					return this;
+				}
+
+				NumberValidationBuilder<T>* whichIsLessThen(double value)
+				{
+					element.setAttribute("less", Text(value));
+					return this;
+				}
+
+				NumberValidationBuilder<T>* whichIsGreaterThen(double value)
+				{
+					element.setAttribute("greater", Text(value));
+					return this;
+				}
+
+				NumberValidationBuilder<T>* withDefault(double value)
+				{
+					element.setAttribute("default", JSONNumber(value).toString());
+					return this;
+				}
+
+				NumberValidationBuilder<T>* withDefaultNull()
+				{
+					element.setAttribute("default", "null");
+					return this;
+				}
+
+				NumberValidationBuilder<T>* whichCanBeNull()
+				{
+					element.setAttribute("nullable", "true");
+					return this;
+				}
+
+				NumberValidationBuilder<T>* whichIsOptional()
+				{
+					element.setAttribute("optional", "true");
+					return this;
+				}
+
+				T* finishNumber()
+				{
+					T* result = builder(element);
+					delete this;
+					return result;
+				}
+			};
+
+			template<typename T>
+			class BoolValidationBuilder
+			{
+			private:
+				XML::Element element;
+				std::function<T* (XML::Element& element)> builder;
+
+			public:
+				BoolValidationBuilder(std::function<T* (XML::Element& element)> builder)
+					: element("<bool/>"),
+					builder(builder)
+				{}
+
+				BoolValidationBuilder<T>* whichIs(bool value)
+				{
+					element.setAttribute("equals", value ? "true" : "false");
+					return this;
+				}
+
+				BoolValidationBuilder<T>* withDefault(bool value)
+				{
+					element.setAttribute("default", JSONBool(value).toString());
+					return this;
+				}
+
+				BoolValidationBuilder<T>* withDefaultNull()
+				{
+					element.setAttribute("default", "null");
+					return this;
+				}
+
+				BoolValidationBuilder<T>* whichCanBeNull()
+				{
+					element.setAttribute("nullable", "true");
+					return this;
+				}
+
+				BoolValidationBuilder<T>* whichIsOptional()
+				{
+					element.setAttribute("optional", "true");
+					return this;
+				}
+
+				T* finishBool()
+				{
+					T* result = builder(element);
+					delete this;
+					return result;
+				}
+			};
+
+			template<typename T>
+			class ArrayValidationBuilder;
+
+			template<typename T>
+			class ObjectValidationBuilder
+			{
+			private:
+				XML::Element element;
+				std::function<T* (XML::Element& element)> builder;
+
+			public:
+				ObjectValidationBuilder(std::function<T* (XML::Element& element)> builder)
+					: element("<object></object>"),
+					builder(builder)
+				{}
+
+				NumberValidationBuilder<ObjectValidationBuilder<T>>* withRequiredNumber(Text name)
+				{
+					return new NumberValidationBuilder<ObjectValidationBuilder<T>>([this, name](XML::Element& e)
+						{
+							if (!element.selectChildsByAttribute("name", name).exists())
+							{
+								XML::Element* attr = new XML::Element("<value></value>");
+								attr->setAttribute("name", name);
+								element.addChild(attr);
+							}
+							element.selectChildsByAttribute("name", name).addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				StringValidationBuilder<ObjectValidationBuilder<T>>* withRequiredString(Text name)
+				{
+					return new StringValidationBuilder<ObjectValidationBuilder<T>>([this, name](XML::Element& e)
+						{
+							if (!element.selectChildsByAttribute("name", name).exists())
+							{
+								XML::Element* attr = new XML::Element("<value></value>");
+								attr->setAttribute("name", name);
+								element.addChild(attr);
+							}
+							element.selectChildsByAttribute("name", name).addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				BoolValidationBuilder<ObjectValidationBuilder<T>>* withRequiredBool(Text name)
+				{
+					return new BoolValidationBuilder<ObjectValidationBuilder<T>>([this, name](XML::Element& e)
+						{
+							if (!element.selectChildsByAttribute("name", name).exists())
+							{
+								XML::Element* attr = new XML::Element("<value></value>");
+								attr->setAttribute("name", name);
+								element.addChild(attr);
+							}
+							element.selectChildsByAttribute("name", name).addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				ArrayValidationBuilder<ObjectValidationBuilder<T>>* withRequiredArray(Text name)
+				{
+					return new ArrayValidationBuilder<ObjectValidationBuilder<T>>([this, name](XML::Element& e)
+						{
+							if (!element.selectChildsByAttribute("name", name).exists())
+							{
+								XML::Element* attr = new XML::Element("<value></value>");
+								attr->setAttribute("name", name);
+								element.addChild(attr);
+							}
+							element.selectChildsByAttribute("name", name).addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				ObjectValidationBuilder<ObjectValidationBuilder<T>>* withRequiredObject(Text name)
+				{
+					return new ObjectValidationBuilder<ObjectValidationBuilder<T>>([this, name](XML::Element& e)
+						{
+							if (!element.selectChildsByAttribute("name", name).exists())
+							{
+								XML::Element* attr = new XML::Element("<value></value>");
+								attr->setAttribute("name", name);
+								element.addChild(attr);
+							}
+							element.selectChildsByAttribute("name", name).addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				ObjectValidationBuilder<T>* withDefault(JSONObject* zObj)
+				{
+					element.setAttribute("default", zObj->toString());
+					return this;
+				}
+
+				ObjectValidationBuilder<T>* withDefaultNull()
+				{
+					element.setAttribute("default", "null");
+					return this;
+				}
+
+				ObjectValidationBuilder<T>* whichCanBeNull()
+				{
+					element.setAttribute("nullable", "true");
+					return this;
+				}
+
+				ObjectValidationBuilder<T>* whichIsOptional()
+				{
+					element.setAttribute("optional", "true");
+					return this;
+				}
+
+				ArrayValidationBuilder<T>* typeOfValuesSpecifiedByAttribute(Text valueName, Text attributeName)
+				{
+					if (!element.selectChildsByAttribute("name", valueName).exists())
+					{
+						XML::Element* attr = new XML::Element("<value></value>");
+						attr->setAttribute("name", valueName);
+						element.addChild(attr);
+					}
+					element.selectChildsByAttribute("name", valueName).setAttribute("typeSpecifiedBy", attributeName);
+					return this;
+				}
+
+				T* finishObject()
+				{
+					T* result = builder(element);
+					delete this;
+					return result;
+				}
+			};
+
+			template<typename T>
+			class ArrayValidationBuilder
+			{
+			private:
+				XML::Element element;
+				std::function<T* (XML::Element& element)> builder;
+
+			public:
+				ArrayValidationBuilder(std::function<T* (XML::Element& element)> builder)
+					: element("<array></array>"),
+					builder(builder)
+				{}
+
+				StringValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedStringInArray()
+				{
+					return new StringValidationBuilder<ArrayValidationBuilder<T>>([this](XML::Element& e)
+						{
+							element.addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				NumberValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedNumberInArray()
+				{
+					return new NumberValidationBuilder<ArrayValidationBuilder<T>>([this](XML::Element& e)
+						{
+							element.addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				BoolValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedBooleanInArray()
+				{
+					return new BoolValidationBuilder<ArrayValidationBuilder<T>>([this](XML::Element& e)
+						{
+							element.addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				ObjectValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedObjectInArray()
+				{
+					return new ObjectValidationBuilder<ArrayValidationBuilder<T>>([this](XML::Element& e)
+						{
+							element.addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				ArrayValidationBuilder<ArrayValidationBuilder<T>>* addAcceptedArrayInArray()
+				{
+					return new ArrayValidationBuilder<ArrayValidationBuilder<T>>([this](XML::Element& e)
+						{
+							element.addChild(e.dublicate());
+							return this;
+						});
+				}
+
+				ArrayValidationBuilder<T>* acceptNullsInArray()
+				{
+					element.setAttribute("nullsEnabled", "true");
+					return this;
+				}
+
+				ArrayValidationBuilder<T>* withDefault(JSONArray* zArray)
+				{
+					element.setAttribute("default", zArray->toString());
+				}
+
+				ArrayValidationBuilder<T>* withDefaultNull()
+				{
+					element.setAttribute("default", "null");
+				}
+
+				ArrayValidationBuilder<T>* whichCanBeNull()
+				{
+					element.setAttribute("nullable", "true");
+					return this;
+				}
+
+				ArrayValidationBuilder<T>* whichIsOptional()
+				{
+					element.setAttribute("optional", "true");
+					return this;
+				}
+
+				ArrayValidationBuilder<T>* typeSpecifiedByAttribute(Text name)
+				{
+					element.setAttribute("typeSpecifiedBy", name);
+					return this;
+				}
+
+				T* finishArray()
+				{
+					T* result = builder(element);
+					delete this;
+					return result;
+				}
+			};
+
+			class JSONValidationResult : public Framework::ReferenceCounter
+			{
+			public:
+				JSONValidationResult();
+				virtual ~JSONValidationResult();
+				virtual bool isValid() const = 0;
+				virtual void printInvalidInfo(int indent = 0) const = 0;
+				virtual JSONValue* getValidPart() const = 0;
+				virtual Text getPath() const = 0;
+				virtual bool isDifferent(const JSONValidationResult* zResult, Text additionalPath) const = 0;
+			};
+
+			class JSONTypeMissmatch : public JSONValidationResult
+			{
+			private:
+				Text path;
+				JSONValue* foundValue;
+				XML::Element* expected;
+				JSONValidationResult* reason;
+			public:
+				JSONTypeMissmatch(Text path, JSONValue* foundValue, XML::Element* expected, JSONValidationResult* reason);
+				~JSONTypeMissmatch();
+				bool isValid() const override;
+				void printInvalidInfo(int indent) const override;
+				JSONValue* getValidPart() const override;
+				Text getPath() const override;
+				bool isDifferent(const JSONValidationResult* zResult, Text additionalPath) const override;
+			};
+
+			class JSONUnknownValue : public JSONValidationResult
+			{
+			private:
+				Text path;
+				JSONValue* foundValue;
+
+			public:
+				JSONUnknownValue(Text path, JSONValue* foundValue);
+				~JSONUnknownValue();
+				bool isValid() const override;
+				void printInvalidInfo(int indent) const override;
+				JSONValue* getValidPart() const override;
+				Text getPath() const override;
+				bool isDifferent(const JSONValidationResult* zResult, Text additionalPath) const override;
+			};
+
+			class JSONMissingValue : public JSONValidationResult
+			{
+			private:
+				Text path;
+				XML::Element* expected;
+
+			public:
+				JSONMissingValue(Text path, XML::Element* expected);
+				~JSONMissingValue();
+				bool isValid() const override;
+				void printInvalidInfo(int indent) const override;
+				JSONValue* getValidPart() const override;
+				Text getPath() const override;
+				bool isDifferent(const JSONValidationResult* zResult, Text additionalPath) const override;
+			};
+
+			class JSONMissingOneOf : public JSONValidationResult
+			{
+			private:
+				Text path;
+				RCArray<XML::Element> expected;
+
+			public:
+				JSONMissingOneOf(Text path, XML::Editor expected);
+				~JSONMissingOneOf();
+				bool isValid() const override;
+				void printInvalidInfo(int indent) const override;
+				JSONValue* getValidPart() const override;
+				Text getPath() const override;
+				bool isDifferent(const JSONValidationResult* zResult, Text additionalPath) const override;
+			};
+
+			class JSONNoTypeMatching : public JSONValidationResult
+			{
+			private:
+				Text path;
+				JSONValue* foundValue;
+				RCArray<XML::Element> expected;
+				RCArray<JSONValidationResult> reasons;
+
+			public:
+				JSONNoTypeMatching(Text path, JSONValue* foundValue, RCArray<XML::Element>& expected, RCArray<JSONValidationResult>& reasons);
+				~JSONNoTypeMatching();
+				bool isValid() const override;
+				void printInvalidInfo(int indent) const override;
+				JSONValue* getValidPart() const override;
+				Text getPath() const override;
+				bool isDifferent(const JSONValidationResult* zResult, Text additionalPath) const override;
+			};
+
+			class JSONValidValue : public JSONValidationResult
+			{
+			private:
+				Text path;
+				JSONValue* value;
+
+			public:
+				JSONValidValue(Text path, JSONValue* value);
+				~JSONValidValue();
+				bool isValid() const override;
+				void printInvalidInfo(int indent) const override;
+				JSONValue* getValidPart() const override;
+				Text getPath() const override;
+				bool isDifferent(const JSONValidationResult* zResult, Text additionalPath) const override;
+			};
+
+			class JSONValidator : public Framework::ReferenceCounter
+			{
+			private:
+				XML::Element* constraints;
+
+			public:
+				__declspec(dllexport) JSONValidator(XML::Element* constraints);
+				__declspec(dllexport) ~JSONValidator();
+				__declspec(dllexport) JSONValidationResult* validate(JSONValue* zValue) const;
+				__declspec(dllexport) bool isValid(JSONValue* zValue) const;
+				/**
+				* returns the valid part of the json by performing the following operations in the specified order untill no further changes are made:
+				* - invalid or unknown object properties are removed
+				* - missing object properties with default values are added if missing
+				* - invalid array elements are removed
+				*
+				* @param zValue the json value to to extract the valid part without increased reference counter
+				* @return the valid part or 0 if no valid part exists
+				*/
+				__declspec(dllexport) JSONValue* getValidParts(JSONValue* zValue) const;
+				__declspec(dllexport) XML::Element* zConstraints();
+
+			private:
+				__declspec(dllexport) JSONValidationResult* validate(JSONValue* zValue, XML::Element* zConstraints, Text path) const;
+				__declspec(dllexport) JSONValidationResult* validateMultipleTypes(JSONValue* zChildValue, XML::Element* zPossibleChildConstraints, Text childPath) const;
+
+			public:
+				__declspec(dllexport) static StringValidationBuilder<JSONValidator>* buildForString();
+				__declspec(dllexport) static NumberValidationBuilder<JSONValidator>* buildForNumber();
+				__declspec(dllexport) static BoolValidationBuilder<JSONValidator>* buildForBool();
+				__declspec(dllexport) static ObjectValidationBuilder<JSONValidator>* buildForObject();
+				__declspec(dllexport) static ArrayValidationBuilder<JSONValidator>* buildForArray();
+			};
+		}
 	}
 }

+ 520 - 520
UIMLView.cpp

@@ -15,616 +15,616 @@ using namespace Framework;
 
 // Erstellt eine UIML View
 UIMLView::UIMLView()
-    : ZeichnungHintergrund()
+	: ZeichnungHintergrund()
 {
-    style = Style::MEIgnoreInside | Style::MEIgnoreParentInside | Style::MEIgnoreSichtbar | Style::MEIgnoreVerarbeitet;
-    members = new Trie< Zeichnung >();
-    dom = 0;
-    nextId = 0;
-    memset( &init, 0, sizeof( UIInit ) );
+	style = Style::MEIgnoreInside | Style::MEIgnoreParentInside | Style::MEIgnoreSichtbar | Style::MEIgnoreVerarbeitet;
+	members = new Trie< Zeichnung >();
+	dom = 0;
+	nextId = 0;
+	memset(&init, 0, sizeof(UIInit));
 }
 
 // Erstellt eine UIML View zu einem UIML Text
 //  uiml: Ein xml element gemät des ksg uiml standarts
-UIMLView::UIMLView( XML::Element *uiml, UIInit &init )
-    : ZeichnungHintergrund()
+UIMLView::UIMLView(XML::Element* uiml, UIInit& init)
+	: ZeichnungHintergrund()
 {
-    this->init = init;
-    members = new Trie< Zeichnung >();
-    dom = 0;
-    nextId = 0;
-    setUIML( uiml );
+	this->init = init;
+	members = new Trie< Zeichnung >();
+	dom = 0;
+	nextId = 0;
+	setUIML(uiml);
 }
 
 // Erstellt eine UIML View zu einem UIML Text
 //  uiml: Ein xml text gemät des ksg uiml standarts
-UIMLView::UIMLView( Text uiml, UIInit &init )
+UIMLView::UIMLView(Text uiml, UIInit& init)
 {
-    this->init = init;
-    members = new Trie< Zeichnung >();
-    dom = 0;
-    setUIML( uiml );
+	this->init = init;
+	members = new Trie< Zeichnung >();
+	dom = 0;
+	setUIML(uiml);
 }
 
 UIMLView::~UIMLView()
 {
-    if( dom )
-        dom->release();
-    members->release();
+	if (dom)
+		dom->release();
+	members->release();
 }
 
 // Verarbeitet ein Maus Ereignis. Wird vom Framework automatisch aufgerufen.
 //  me: Das Ereignis
-void UIMLView::doMausEreignis( MausEreignis &me, bool userRet )
+void UIMLView::doMausEreignis(MausEreignis& me, bool userRet)
 {
-    if( dom )
-    {
-        bool verarbeitet = me.verarbeitet;
-        me.verarbeitet |= hatStyleNicht( Style::Sichtbar );
-        bool insideParent = me.insideParent;
-        if( !hatStyle( Style::Sichtbar ) || !me.insideParent || me.verarbeitet || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y || !userRet )
-            me.insideParent = 0;
-        int rbr = 0;
-        if( hatStyle( Style::Rahmen ) && rahmen )
-            rbr = rahmen->getRBreite();
-        me.mx -= rbr;
-        me.my -= rbr;
-        if( hatStyle( Style::VScroll ) && vertikalScrollBar )
-            me.my += vertikalScrollBar->getScroll();
-        if( hatStyle( Style::HScroll ) && horizontalScrollBar )
-            me.mx += horizontalScrollBar->getScroll();
-        if( dom )
-        {
-            for( auto i = dom->getChilds(); i; i++ )
-            { // TODO render elements backwards
-                Zeichnung *z = members->z( i->getAttributeValue( "id" ), i->getAttributeValue( "id" ).getLength() );
-                if( z )
-                    z->doPublicMausEreignis( me );
-            }
-        }
-        me.mx += rbr;
-        me.my += rbr;
-        if( hatStyle( Style::VScroll ) && vertikalScrollBar )
-            me.my -= vertikalScrollBar->getScroll();
-        if( hatStyle( Style::HScroll ) && horizontalScrollBar )
-            me.mx -= horizontalScrollBar->getScroll();
-        if( !hatStyle( Style::Sichtbar ) || !me.insideParent || me.verarbeitet || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y || !userRet )
-            me.insideParent = insideParent;
-        else
-            me.verarbeitet = 1;
-        if( hatStyleNicht( Style::Sichtbar ) )
-            me.verarbeitet = verarbeitet;
-    }
+	if (dom)
+	{
+		bool verarbeitet = me.verarbeitet;
+		me.verarbeitet |= hatStyleNicht(Style::Sichtbar);
+		bool insideParent = me.insideParent;
+		if (!hatStyle(Style::Sichtbar) || !me.insideParent || me.verarbeitet || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y || !userRet)
+			me.insideParent = 0;
+		int rbr = 0;
+		if (hatStyle(Style::Rahmen) && rahmen)
+			rbr = rahmen->getRBreite();
+		me.mx -= rbr;
+		me.my -= rbr;
+		if (hatStyle(Style::VScroll) && vertikalScrollBar)
+			me.my += vertikalScrollBar->getScroll();
+		if (hatStyle(Style::HScroll) && horizontalScrollBar)
+			me.mx += horizontalScrollBar->getScroll();
+		if (dom)
+		{
+			for (auto i = dom->getChilds(); i; i++)
+			{ // TODO render elements backwards
+				Zeichnung* z = members->z(i->getAttributeValue("id"), i->getAttributeValue("id").getLength());
+				if (z)
+					z->doPublicMausEreignis(me);
+			}
+		}
+		me.mx += rbr;
+		me.my += rbr;
+		if (hatStyle(Style::VScroll) && vertikalScrollBar)
+			me.my -= vertikalScrollBar->getScroll();
+		if (hatStyle(Style::HScroll) && horizontalScrollBar)
+			me.mx -= horizontalScrollBar->getScroll();
+		if (!hatStyle(Style::Sichtbar) || !me.insideParent || me.verarbeitet || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y || !userRet)
+			me.insideParent = insideParent;
+		else
+			me.verarbeitet = 1;
+		if (hatStyleNicht(Style::Sichtbar))
+			me.verarbeitet = verarbeitet;
+	}
 }
 
-void UIMLView::parseTable( Iterator<XML::Element *> childs, ObjTabelle *table )
+void UIMLView::parseTable(Iterator<XML::Element*> childs, ObjTabelle* table)
 {
-    for( auto i = childs; i; i++ )
-    {
-        Text id;
-        if( i->hasAttribute( "id" ) )
-            id = i->getAttributeValue( "id" );
-        else
-        {
-            id = Text( "_" ) += nextId++;
-            i->setAttribute( "id", id );
-        }
-        if( i->getName().istGleich( "tr" ) )
-        {
-            table->addZeile( id );
-            Text line = id;
-            int c = 1;
-            for( auto j = i->getChilds(); j; j++ )
-            {
-                Zeichnung *z = parseElement( j._ );
-                if( table->getSpaltenAnzahl() < c )
-                    table->addSpalte( Text( c - 1 ) );
-                if( z )
-                    table->setZeichnungZ( (char *)Text( c - 1 ), (char *)line, dynamic_cast<Zeichnung *>(z->getThis()) );
-                c++;
-            }
-        }
-    }
+	for (auto i = childs; i; i++)
+	{
+		Text id;
+		if (i->hasAttribute("id"))
+			id = i->getAttributeValue("id");
+		else
+		{
+			id = Text("_") += nextId++;
+			i->setAttribute("id", id);
+		}
+		if (i->getName().istGleich("tr"))
+		{
+			table->addZeile(id);
+			Text line = id;
+			int c = 1;
+			for (auto j = i->getChilds(); j; j++)
+			{
+				Zeichnung* z = parseElement(j._);
+				if (table->getSpaltenAnzahl() < c)
+					table->addSpalte(Text(c - 1));
+				if (z)
+					table->setZeichnungZ((char*)Text(c - 1), (char*)line, dynamic_cast<Zeichnung*>(z->getThis()));
+				c++;
+			}
+		}
+	}
 }
 
-void UIMLView::parseFrame( Iterator<XML::Element *> childs, Fenster *frame )
+void UIMLView::parseFrame(Iterator<XML::Element*> childs, Fenster* frame)
 {
-    for( auto i = childs; i; i++ )
-    {
-        Zeichnung *z = parseElement( i._ );
-        if( z )
-            frame->addMember( dynamic_cast<Zeichnung *>(z->getThis()) );
-    }
+	for (auto i = childs; i; i++)
+	{
+		Zeichnung* z = parseElement(i._);
+		if (z)
+			frame->addMember(dynamic_cast<Zeichnung*>(z->getThis()));
+	}
 }
 
-Zeichnung *UIMLView::parseElement( XML::Element *e )
+Zeichnung* UIMLView::parseElement(XML::Element* e)
 {
-    Text id;
-    if( e->hasAttribute( "id" ) )
-        id = e->getAttributeValue( "id" );
-    else
-    {
-        id = Text( "_" ) += nextId++;
-        e->setAttribute( "id", id );
-    }
-    Zeichnung *z = members->z( id, id.getLength() );
-    if( !z )
-    {
-        // precompute attributes
-        if( e->hasAttribute( "margin" ) )
-        {
-            Text m = e->getAttributeValue( "margin" );
-            if( !e->hasAttribute( "margin-left" ) )
-                e->setAttribute( "margin-left", m );
-            if( !e->hasAttribute( "margin-top" ) )
-                e->setAttribute( "margin-top", m );
-            if( !e->hasAttribute( "margin-right" ) )
-                e->setAttribute( "margin-right", m );
-            if( !e->hasAttribute( "margin-bottom" ) )
-                e->setAttribute( "margin-bottom", m );
-        }
-        if( e->hasAttribute( "class" ) )
-        {
-            Text c = e->getAttributeValue( "class" );
-            while( 1 )
-            {
-                Text *t;
-                if( c.hat( "," ) )
-                    t = c.getTeilText( 0, c.positionVon( ',' ) );
-                else
-                    t = new Text( c );
-                XML::Editor ce = dom->selectChildsByName( "class" ).whereAttributeEquals( "id", *t );
-                for( auto i = ce.getIterator(); i; i++ )
-                {
-                    for( auto j = i->getAttributeNames(), k = i->getAttributeValues(); j && k; j++, k++ )
-                    {
-                        if( !e->hasAttribute( j->getText() ) )
-                            e->setAttribute( j->getText(), i->getText() );
-                    }
-                }
-                t->release();
-                if( c.hat( "," ) )
-                    c.remove( 0, c.positionVon( ',' + 1 ) );
-                else
-                    break;
-            }
-        }
-        if( e->hasAttribute( "text-align" ) )
-        {
-            if( !e->hasAttribute( "text-align-horizontal" ) )
-                e->setAttribute( "text-align-horizontal", e->getAttributeValue( "text-align" ) );
-            if( !e->hasAttribute( "text-align-vertical" ) )
-                e->setAttribute( "text-align-vertical", e->getAttributeValue( "text-align" ) );
-        }
-        // create objects
-        if( e->getName().istGleich( "textfield" ) ||
-            e->getName().istGleich( "text" ) ||
-            e->getName().istGleich( "textarea" ) )
-        {
-            TextFeld *t = init.createTextFeld( init.initParam );
-            if( e->getName().istGleich( "textfield" ) )
-                t->addStyle( TextFeld::Style::TextFeld );
-            if( e->getName().istGleich( "text" ) )
-                t->addStyle( TextFeld::Style::Text );
-            if( e->getName().istGleich( "textarea" ) )
-                t->addStyle( TextFeld::Style::TextGebiet );
-            t->setText( e->getText() );
-            if( e->hasAttribute( "font-size" ) )
-                t->setSchriftSize( (unsigned char)(int)e->getAttributeValue( "font-size" ) );
-            if( e->hasAttribute( "text-align-horizontal" ) )
-            {
-                if( e->getAttributeValue( "text-align-horizontal" ).istGleich( "center" ) )
-                    t->addStyle( TextFeld::Style::HCenter );
-            }
-            if( e->hasAttribute( "text-align-vertical" ) )
-            {
-                if( e->getAttributeValue( "text-align-vertical" ).istGleich( "center" ) )
-                    t->addStyle( TextFeld::Style::VCenter );
-            }
-            if( e->hasAttribute( "disabled" ) )
-                t->removeStyle( TextFeld::Style::Editierbar );
-            z = t;
-        }
-        if( e->getName().istGleich( "button" ) )
-        {
-            Knopf *k = init.createKnopf( init.initParam );
-            k->setText( e->getText() );
-            if( e->hasAttribute( "font-size" ) )
-                k->setSchriftSize( (unsigned char)(int)e->getAttributeValue( "font-size" ) );
-            z = k;
-        }
-        if( e->getName().istGleich( "check" ) )
-        {
-            KontrollKnopf *k = init.createKontrollKnopf( init.initParam );
-            k->setText( e->getText() );
-            k->setSText( e->getText() );
-            k->setStyle( KontrollKnopf::Style::Selected, e->hasAttribute( "selected" ) );
-            if( e->hasAttribute( "font-size" ) )
-                k->setSSize( (unsigned char)(int)e->getAttributeValue( "font-size" ) );
-            z = k;
-        }
-        if( e->getName().istGleich( "table" ) )
-        {
-            ObjTabelle *t = init.createObjTabelle( init.initParam );
-            parseTable( e->getChilds(), t );
-            if( e->hasAttribute( "scroll" ) )
-            {
-                if( e->getAttributeValue( "scroll" ).istGleich( "horizontal" ) )
-                    t->addStyle( ObjTabelle::Style::HScroll );
-                if( e->getAttributeValue( "scroll" ).istGleich( "vertical" ) )
-                    t->addStyle( ObjTabelle::Style::VScroll );
-                if( e->getAttributeValue( "scroll" ).istGleich( "both" ) )
-                    t->addStyle( ObjTabelle::Style::scroll );
-            }
-            z = t;
-        }
-        if( e->getName().istGleich( "frame" ) )
-        {
-            Fenster *f = init.createFenster( init.initParam );
-            parseFrame( e->getChilds(), f );
-            if( e->hasAttribute( "title" ) )
-                f->setTitel( e->getAttributeValue( "title" ) );
-            if( e->hasAttribute( "title-height" ) )
-                f->zTTextFeld()->setSize( f->zTTextFeld()->getBreite(), e->getAttributeValue( "title-height" ) );
-            z = f;
-        }
-        // add general attributes
-        if( z && e->hasAttribute( "tooltip" ) )
-            z->setToolTipText( e->getAttributeValue( "tooltip" ), init.initParam.bildschirm, init.initParam.schrift );
-        if( z && e->hasAttribute( "style" ) )
-            z->setStyle( (__int64)e->getAttributeValue( "style" ) );
-        if( z && e->hasAttribute( "hidden" ) )
-            z->removeStyle( Zeichnung::Style::Sichtbar );
-        if( z && e->hasAttribute( "disabled" ) )
-            z->removeStyle( Zeichnung::Style::Erlaubt );
-        if( z )
-            members->set( id, id.getLength(), z );
-    }
-    return z;
+	Text id;
+	if (e->hasAttribute("id"))
+		id = e->getAttributeValue("id");
+	else
+	{
+		id = Text("_") += nextId++;
+		e->setAttribute("id", id);
+	}
+	Zeichnung* z = members->z(id, id.getLength());
+	if (!z)
+	{
+		// precompute attributes
+		if (e->hasAttribute("margin"))
+		{
+			Text m = e->getAttributeValue("margin");
+			if (!e->hasAttribute("margin-left"))
+				e->setAttribute("margin-left", m);
+			if (!e->hasAttribute("margin-top"))
+				e->setAttribute("margin-top", m);
+			if (!e->hasAttribute("margin-right"))
+				e->setAttribute("margin-right", m);
+			if (!e->hasAttribute("margin-bottom"))
+				e->setAttribute("margin-bottom", m);
+		}
+		if (e->hasAttribute("class"))
+		{
+			Text c = e->getAttributeValue("class");
+			while (1)
+			{
+				Text* t;
+				if (c.hat(","))
+					t = c.getTeilText(0, c.positionVon(','));
+				else
+					t = new Text(c);
+				XML::Editor ce = dom->selectChildsByName("class").whereAttributeEquals("id", *t);
+				for (auto i = ce.begin(); i; i++)
+				{
+					for (auto j = i->getAttributeNames(), k = i->getAttributeValues(); j && k; j++, k++)
+					{
+						if (!e->hasAttribute(j->getText()))
+							e->setAttribute(j->getText(), i->getText());
+					}
+				}
+				t->release();
+				if (c.hat(","))
+					c.remove(0, c.positionVon(',' + 1));
+				else
+					break;
+			}
+		}
+		if (e->hasAttribute("text-align"))
+		{
+			if (!e->hasAttribute("text-align-horizontal"))
+				e->setAttribute("text-align-horizontal", e->getAttributeValue("text-align"));
+			if (!e->hasAttribute("text-align-vertical"))
+				e->setAttribute("text-align-vertical", e->getAttributeValue("text-align"));
+		}
+		// create objects
+		if (e->getName().istGleich("textfield") ||
+			e->getName().istGleich("text") ||
+			e->getName().istGleich("textarea"))
+		{
+			TextFeld* t = init.createTextFeld(init.initParam);
+			if (e->getName().istGleich("textfield"))
+				t->addStyle(TextFeld::Style::TextFeld);
+			if (e->getName().istGleich("text"))
+				t->addStyle(TextFeld::Style::Text);
+			if (e->getName().istGleich("textarea"))
+				t->addStyle(TextFeld::Style::TextGebiet);
+			t->setText(e->getText());
+			if (e->hasAttribute("font-size"))
+				t->setSchriftSize((unsigned char)(int)e->getAttributeValue("font-size"));
+			if (e->hasAttribute("text-align-horizontal"))
+			{
+				if (e->getAttributeValue("text-align-horizontal").istGleich("center"))
+					t->addStyle(TextFeld::Style::HCenter);
+			}
+			if (e->hasAttribute("text-align-vertical"))
+			{
+				if (e->getAttributeValue("text-align-vertical").istGleich("center"))
+					t->addStyle(TextFeld::Style::VCenter);
+			}
+			if (e->hasAttribute("disabled"))
+				t->removeStyle(TextFeld::Style::Editierbar);
+			z = t;
+		}
+		if (e->getName().istGleich("button"))
+		{
+			Knopf* k = init.createKnopf(init.initParam);
+			k->setText(e->getText());
+			if (e->hasAttribute("font-size"))
+				k->setSchriftSize((unsigned char)(int)e->getAttributeValue("font-size"));
+			z = k;
+		}
+		if (e->getName().istGleich("check"))
+		{
+			KontrollKnopf* k = init.createKontrollKnopf(init.initParam);
+			k->setText(e->getText());
+			k->setSText(e->getText());
+			k->setStyle(KontrollKnopf::Style::Selected, e->hasAttribute("selected"));
+			if (e->hasAttribute("font-size"))
+				k->setSSize((unsigned char)(int)e->getAttributeValue("font-size"));
+			z = k;
+		}
+		if (e->getName().istGleich("table"))
+		{
+			ObjTabelle* t = init.createObjTabelle(init.initParam);
+			parseTable(e->getChilds(), t);
+			if (e->hasAttribute("scroll"))
+			{
+				if (e->getAttributeValue("scroll").istGleich("horizontal"))
+					t->addStyle(ObjTabelle::Style::HScroll);
+				if (e->getAttributeValue("scroll").istGleich("vertical"))
+					t->addStyle(ObjTabelle::Style::VScroll);
+				if (e->getAttributeValue("scroll").istGleich("both"))
+					t->addStyle(ObjTabelle::Style::scroll);
+			}
+			z = t;
+		}
+		if (e->getName().istGleich("frame"))
+		{
+			Fenster* f = init.createFenster(init.initParam);
+			parseFrame(e->getChilds(), f);
+			if (e->hasAttribute("title"))
+				f->setTitel(e->getAttributeValue("title"));
+			if (e->hasAttribute("title-height"))
+				f->zTTextFeld()->setSize(f->zTTextFeld()->getBreite(), e->getAttributeValue("title-height"));
+			z = f;
+		}
+		// add general attributes
+		if (z && e->hasAttribute("tooltip"))
+			z->setToolTipText(e->getAttributeValue("tooltip"), init.initParam.bildschirm, init.initParam.schrift);
+		if (z && e->hasAttribute("style"))
+			z->setStyle((__int64)e->getAttributeValue("style"));
+		if (z && e->hasAttribute("hidden"))
+			z->removeStyle(Zeichnung::Style::Sichtbar);
+		if (z && e->hasAttribute("disabled"))
+			z->removeStyle(Zeichnung::Style::Erlaubt);
+		if (z)
+			members->set(id, id.getLength(), z);
+	}
+	return z;
 }
 
-void UIMLView::layout( XML::Element *e, int pWidth, int pHeight )
+void UIMLView::layout(XML::Element* e, int pWidth, int pHeight)
 {
-    Text id = e->getAttributeValue( "id" );
-    Zeichnung *z = members->z( id, id.getLength() );
-    if( z )
-    {
-        int width = z->getBreite();
-        int height = z->getHeight();
-        if( e->hasAttribute( "width" ) )
-        {
-            Text w = e->getAttributeValue( "width" );
-            width = w;
-            if( w.getText()[ w.getLength() - 1 ] == '%' )
-                width = (int)((pWidth / 100.0) * width);
-        }
-        if( e->hasAttribute( "height" ) )
-        {
-            Text h = e->getAttributeValue( "height" );
-            height = h;
-            if( h.getText()[ h.getLength() - 1 ] == '%' )
-                height = (int)((pHeight / 100.0) * height);
-        }
-        z->setSize( width, height );
-        if( e->hasAttribute( "align-left" ) )
-        {
-            Text la = e->getAttributeValue( "align-left" );
-            int x = 0;
-            if( la.istGleich( "start" ) )
-                x = 0;
-            else if( la.istGleich( "end" ) )
-                x = pWidth;
-            else
-            {
-                XML::Editor ed = e->zParent()->selectChildsByAttribute( "id", la );
-                for( auto i = ed.getIterator(); i; i++ )
-                    layout( i, pWidth, pHeight );
-                Zeichnung *laz = members->z( la, la.getLength() );
-                if( laz )
-                    x = laz->getX() + laz->getBreite();
-            }
-            if( e->hasAttribute( "margin-left" ) )
-            {
-                Text mt = e->getAttributeValue( "margin-left" );
-                int m = mt;
-                if( mt.getText()[ mt.getLength() - 1 ] == '%' )
-                    m = (int)((pWidth / 100.0) * m);
-                x += m;
-            }
-            z->setX( x );
-        }
-        else if( e->hasAttribute( "align-right" ) )
-        {
-            Text ra = e->getAttributeValue( "align-right" );
-            int x = 0;
-            if( ra.istGleich( "start" ) )
-                x = -z->getBreite();
-            else if( ra.istGleich( "end" ) )
-                x = pWidth - z->getBreite();
-            else
-            {
-                XML::Editor ed = e->zParent()->selectChildsByAttribute( "id", ra );
-                for( auto i = ed.getIterator(); i; i++ )
-                    layout( i, pWidth, pHeight );
-                Zeichnung *raz = members->z( ra, ra.getLength() );
-                if( raz )
-                    x = raz->getX() - z->getBreite();
-            }
-            if( e->hasAttribute( "margin-right" ) )
-            {
-                Text mt = e->getAttributeValue( "margin-right" );
-                int m = mt;
-                if( mt.getText()[ mt.getLength() - 1 ] == '%' )
-                    m = (int)((pWidth / 100.0) * m);
-                x -= m;
-            }
-            z->setX( x );
-        }
-        if( e->hasAttribute( "align-top" ) )
-        {
-            Text ta = e->getAttributeValue( "align-top" );
-            int y = 0;
-            if( ta.istGleich( "start" ) )
-                y = 0;
-            else if( ta.istGleich( "end" ) )
-                y = pHeight;
-            else
-            {
-                XML::Editor ed = e->zParent()->selectChildsByAttribute( "id", ta );
-                for( auto i = ed.getIterator(); i; i++ )
-                    layout( i, pWidth, pHeight );
-                Zeichnung *taz = members->z( ta, ta.getLength() );
-                if( taz )
-                    y = taz->getY() + taz->getHeight();
-            }
-            if( e->hasAttribute( "margin-top" ) )
-            {
-                Text mt = e->getAttributeValue( "margin-top" );
-                int m = mt;
-                if( mt.getText()[ mt.getLength() - 1 ] == '%' )
-                    m = (int)((pHeight / 100.0) * m);
-                y += m;
-            }
-            z->setY( y );
-        }
-        else if( e->hasAttribute( "align-bottom" ) )
-        {
-            Text ba = e->getAttributeValue( "align-bottom" );
-            int y = 0;
-            if( ba.istGleich( "start" ) )
-                y = -z->getHeight();
-            else if( ba.istGleich( "end" ) )
-                y = pHeight - z->getHeight();
-            else
-            {
-                XML::Editor ed = e->zParent()->selectChildsByAttribute( "id", ba );
-                for( auto i = ed.getIterator(); i; i++ )
-                    layout( i, pWidth, pHeight );
-                Zeichnung *baz = members->z( ba, ba.getLength() );
-                if( baz )
-                    y = baz->getY() - z->getHeight();
-            }
-            if( e->hasAttribute( "margin-bottom" ) )
-            {
-                Text mt = e->getAttributeValue( "margin-bottom" );
-                int m = mt;
-                if( mt.getText()[ mt.getLength() - 1 ] == '%' )
-                    m = (int)((pHeight / 100.0) * m);
-                y -= m;
-            }
-            z->setY( y );
-        }
-        int x = z->getX();
-        int y = z->getY();
-        if( e->hasAttribute( "x" ) )
-        {
-            Text xt = e->getAttributeValue( "x" );
-            x = xt;
-            if( xt.getText()[ xt.getLength() - 1 ] == '%' )
-                x = (int)((pWidth / 100.0) * x);
-        }
-        if( e->hasAttribute( "y" ) )
-        {
-            Text yt = e->getAttributeValue( "y" );
-            y = yt;
-            if( yt.getText()[ yt.getLength() - 1 ] == '%' )
-                y = (int)((pHeight / 100.0) * y);
-        }
-        z->setPosition( x, y );
-        if( e->getName().istGleich( "textarea" ) )
-        {
-            ((TextFeld *)z)->zTextRenderer()->textFormatieren( ((TextFeld *)z)->zText(), z->getInnenBreite() );
-        }
-    }
-    if( z )
-    {
-        pWidth = z->getInnenBreite();
-        pHeight = z->getInnenHeight();
-    }
-    // recursive layout
-    for( auto i = e->getChilds(); i; i++ )
-        layout( i, pWidth, pHeight );
-    if( z )
-    {
-        if( e->getName().istGleich( "table" ) )
-        {
-            ObjTabelle *objT = (ObjTabelle *)z;
-            if( objT->getZeilenAnzahl() > 0 )
-            {
-                if( e->hasAttribute( "line-height" ) )
-                {
-                    int height = e->getAttributeValue( "line-height" );
-                    for( int i = 0; i < objT->getZeilenAnzahl(); i++ )
-                        objT->setZeilenHeight( i, height );
-                }
-                for( int i = 0; i < objT->getSpaltenAnzahl(); i++ )
-                {
-                    if( objT->zZeichnung( i, 0 ) )
-                        objT->setSpaltenBreite( i, objT->zZeichnung( i, 0 )->getBreite() );
-                }
-            }
-        }
-    }
+	Text id = e->getAttributeValue("id");
+	Zeichnung* z = members->z(id, id.getLength());
+	if (z)
+	{
+		int width = z->getBreite();
+		int height = z->getHeight();
+		if (e->hasAttribute("width"))
+		{
+			Text w = e->getAttributeValue("width");
+			width = w;
+			if (w.getText()[w.getLength() - 1] == '%')
+				width = (int)((pWidth / 100.0) * width);
+		}
+		if (e->hasAttribute("height"))
+		{
+			Text h = e->getAttributeValue("height");
+			height = h;
+			if (h.getText()[h.getLength() - 1] == '%')
+				height = (int)((pHeight / 100.0) * height);
+		}
+		z->setSize(width, height);
+		if (e->hasAttribute("align-left"))
+		{
+			Text la = e->getAttributeValue("align-left");
+			int x = 0;
+			if (la.istGleich("start"))
+				x = 0;
+			else if (la.istGleich("end"))
+				x = pWidth;
+			else
+			{
+				XML::Editor ed = e->zParent()->selectChildsByAttribute("id", la);
+				for (auto i = ed.begin(); i; i++)
+					layout(i, pWidth, pHeight);
+				Zeichnung* laz = members->z(la, la.getLength());
+				if (laz)
+					x = laz->getX() + laz->getBreite();
+			}
+			if (e->hasAttribute("margin-left"))
+			{
+				Text mt = e->getAttributeValue("margin-left");
+				int m = mt;
+				if (mt.getText()[mt.getLength() - 1] == '%')
+					m = (int)((pWidth / 100.0) * m);
+				x += m;
+			}
+			z->setX(x);
+		}
+		else if (e->hasAttribute("align-right"))
+		{
+			Text ra = e->getAttributeValue("align-right");
+			int x = 0;
+			if (ra.istGleich("start"))
+				x = -z->getBreite();
+			else if (ra.istGleich("end"))
+				x = pWidth - z->getBreite();
+			else
+			{
+				XML::Editor ed = e->zParent()->selectChildsByAttribute("id", ra);
+				for (auto i = ed.begin(); i; i++)
+					layout(i, pWidth, pHeight);
+				Zeichnung* raz = members->z(ra, ra.getLength());
+				if (raz)
+					x = raz->getX() - z->getBreite();
+			}
+			if (e->hasAttribute("margin-right"))
+			{
+				Text mt = e->getAttributeValue("margin-right");
+				int m = mt;
+				if (mt.getText()[mt.getLength() - 1] == '%')
+					m = (int)((pWidth / 100.0) * m);
+				x -= m;
+			}
+			z->setX(x);
+		}
+		if (e->hasAttribute("align-top"))
+		{
+			Text ta = e->getAttributeValue("align-top");
+			int y = 0;
+			if (ta.istGleich("start"))
+				y = 0;
+			else if (ta.istGleich("end"))
+				y = pHeight;
+			else
+			{
+				XML::Editor ed = e->zParent()->selectChildsByAttribute("id", ta);
+				for (auto i = ed.begin(); i; i++)
+					layout(i, pWidth, pHeight);
+				Zeichnung* taz = members->z(ta, ta.getLength());
+				if (taz)
+					y = taz->getY() + taz->getHeight();
+			}
+			if (e->hasAttribute("margin-top"))
+			{
+				Text mt = e->getAttributeValue("margin-top");
+				int m = mt;
+				if (mt.getText()[mt.getLength() - 1] == '%')
+					m = (int)((pHeight / 100.0) * m);
+				y += m;
+			}
+			z->setY(y);
+		}
+		else if (e->hasAttribute("align-bottom"))
+		{
+			Text ba = e->getAttributeValue("align-bottom");
+			int y = 0;
+			if (ba.istGleich("start"))
+				y = -z->getHeight();
+			else if (ba.istGleich("end"))
+				y = pHeight - z->getHeight();
+			else
+			{
+				XML::Editor ed = e->zParent()->selectChildsByAttribute("id", ba);
+				for (auto i = ed.begin(); i; i++)
+					layout(i, pWidth, pHeight);
+				Zeichnung* baz = members->z(ba, ba.getLength());
+				if (baz)
+					y = baz->getY() - z->getHeight();
+			}
+			if (e->hasAttribute("margin-bottom"))
+			{
+				Text mt = e->getAttributeValue("margin-bottom");
+				int m = mt;
+				if (mt.getText()[mt.getLength() - 1] == '%')
+					m = (int)((pHeight / 100.0) * m);
+				y -= m;
+			}
+			z->setY(y);
+		}
+		int x = z->getX();
+		int y = z->getY();
+		if (e->hasAttribute("x"))
+		{
+			Text xt = e->getAttributeValue("x");
+			x = xt;
+			if (xt.getText()[xt.getLength() - 1] == '%')
+				x = (int)((pWidth / 100.0) * x);
+		}
+		if (e->hasAttribute("y"))
+		{
+			Text yt = e->getAttributeValue("y");
+			y = yt;
+			if (yt.getText()[yt.getLength() - 1] == '%')
+				y = (int)((pHeight / 100.0) * y);
+		}
+		z->setPosition(x, y);
+		if (e->getName().istGleich("textarea"))
+		{
+			((TextFeld*)z)->zTextRenderer()->textFormatieren(((TextFeld*)z)->zText(), z->getInnenBreite());
+		}
+	}
+	if (z)
+	{
+		pWidth = z->getInnenBreite();
+		pHeight = z->getInnenHeight();
+	}
+	// recursive layout
+	for (auto i = e->getChilds(); i; i++)
+		layout(i, pWidth, pHeight);
+	if (z)
+	{
+		if (e->getName().istGleich("table"))
+		{
+			ObjTabelle* objT = (ObjTabelle*)z;
+			if (objT->getZeilenAnzahl() > 0)
+			{
+				if (e->hasAttribute("line-height"))
+				{
+					int height = e->getAttributeValue("line-height");
+					for (int i = 0; i < objT->getZeilenAnzahl(); i++)
+						objT->setZeilenHeight(i, height);
+				}
+				for (int i = 0; i < objT->getSpaltenAnzahl(); i++)
+				{
+					if (objT->zZeichnung(i, 0))
+						objT->setSpaltenBreite(i, objT->zZeichnung(i, 0)->getBreite());
+				}
+			}
+		}
+	}
 }
 
 // setzt den inhalt der view
 //  uiml: Ein xml element gemät des ksg uiml standarts
-void UIMLView::setUIML( XML::Element *uiml )
+void UIMLView::setUIML(XML::Element* uiml)
 {
-    if( dom )
-        dom->release();
-    dom = uiml;
-    members->leeren();
-    nextId = 0;
-    if( dom )
-    {
-        for( auto i = dom->getChilds(); i; i++ )
-        {
-            parseElement( i._ );
-        }
-    }
+	if (dom)
+		dom->release();
+	dom = uiml;
+	members->leeren();
+	nextId = 0;
+	if (dom)
+	{
+		for (auto i = dom->getChilds(); i; i++)
+		{
+			parseElement(i._);
+		}
+	}
 }
 
 // setzt den inhalt der view
 //  uiml: Ein xml text gemät des ksg uiml standarts
-void UIMLView::setUIML( Text uiml )
+void UIMLView::setUIML(Text uiml)
 {
-    setUIML( new XML::Element( uiml ) );
+	setUIML(new XML::Element(uiml));
 }
 
 // Gibt eine zeichnung zurück, welche in uiml eine bestimmte id hat
 //  id: die id der Zeichnung
-Zeichnung *UIMLView::zZeichnung( Text id )
+Zeichnung* UIMLView::zZeichnung(Text id)
 {
-    return members->z( id, id.getLength() );
+	return members->z(id, id.getLength());
 }
 
 // aktualisiert größe und position aller Zeichnungen gemäß den spezifikationen in UIML
 void UIMLView::layout()
 {
-    if( dom )
-    {
-        for( auto i = dom->getChilds(); i; i++ )
-        {
-            layout( i._, this->getInnenBreite(), this->getInnenHeight() );
-        }
-    }
+	if (dom)
+	{
+		for (auto i = dom->getChilds(); i; i++)
+		{
+			layout(i._, this->getInnenBreite(), this->getInnenHeight());
+		}
+	}
 }
 
 // fügt ein element hinzu
 //  uiml: Ein xml text gemät des KSG UIML standarts, welcher das neue Objekt darstellt
-Text UIMLView::addMember( Text uiml )
+Text UIMLView::addMember(Text uiml)
 {
-    XML::Element *e = new XML::Element( uiml );
-    if( parseElement( e ) )
-        dom->addChildAtFront( e );
-    return e->getAttributeValue( "id" );
+	XML::Element* e = new XML::Element(uiml);
+	if (parseElement(e))
+		dom->addChildAtFront(e);
+	return e->getAttributeValue("id");
 }
 
 // fügt ein element zu einem Elternelement hinzu (funktioniert momentan nur mit frame Objekten)
 //  uiml: Ein xml text gemät des KSG UIML standarts, welcher das neue Objekt darstellt
-Text UIMLView::addMember( Text uiml, Text parentId )
+Text UIMLView::addMember(Text uiml, Text parentId)
 {
-    XML::Element *e = new XML::Element( uiml );
-    XML::Editor ed = dom->selectChildren();
-    while( ed.getIterator() )
-    {
-        XML::Editor ed2 = ed.whereAttributeEquals( "id", parentId );
-        if( ed2.getIterator() )
-        {
-            if( ed2.getIterator()->getName().istGleich( "frame" ) )
-            {
-                Zeichnung *z = parseElement( e );
-                if( z )
-                {
-                    dynamic_cast<Fenster *>(members->z( parentId, parentId.getLength() ))->addMember( dynamic_cast<Zeichnung *>(z->getThis()) );
-                    ed2.getIterator()->addChild( e );
-                }
-                return e->getAttributeValue( "id" );
-            }
-        }
-        ed = ed.selectChildren();
-    }
-    e->release();
-    return "";
+	XML::Element* e = new XML::Element(uiml);
+	XML::Editor ed = dom->selectChildren();
+	while (ed.begin())
+	{
+		XML::Editor ed2 = ed.whereAttributeEquals("id", parentId);
+		if (ed2.begin())
+		{
+			if (ed2.begin()->getName().istGleich("frame"))
+			{
+				Zeichnung* z = parseElement(e);
+				if (z)
+				{
+					dynamic_cast<Fenster*>(members->z(parentId, parentId.getLength()))->addMember(dynamic_cast<Zeichnung*>(z->getThis()));
+					ed2.begin()->addChild(e);
+				}
+				return e->getAttributeValue("id");
+			}
+		}
+		ed = ed.selectChildren();
+	}
+	e->release();
+	return "";
 }
 
 // entfernt ein element
 //  id: id des Elements
-void UIMLView::removeMember( Text id )
+void UIMLView::removeMember(Text id)
 {
-    XML::Editor e = dom->selectChildsByAttribute( "id", id );
-    e.remove();
-    members->remove( id, id.getLength() );
+	XML::Editor e = dom->selectChildsByAttribute("id", id);
+	e.remove();
+	members->remove(id, id.getLength());
 }
 
 // Verarbeitet ein Tastatur Ereignis. Wird vom Framework automatisch aufgerufen
 //  te: Das Ereignis
-void UIMLView::doTastaturEreignis( TastaturEreignis &te )
+void UIMLView::doTastaturEreignis(TastaturEreignis& te)
 {
-    bool verarbeitet = te.verarbeitet;
-    ZeichnungHintergrund::doTastaturEreignis( te );
-    te.verarbeitet = verarbeitet;
-    if( dom )
-    {
-        for( auto i = dom->getChilds(); i; i++ )
-        { // TODO render elements backwards
-            Zeichnung *z = members->z( i->getAttributeValue( "id" ), i->getAttributeValue( "id" ).getLength() );
-            if( z )
-                z->doTastaturEreignis( te );
-        }
-    }
+	bool verarbeitet = te.verarbeitet;
+	ZeichnungHintergrund::doTastaturEreignis(te);
+	te.verarbeitet = verarbeitet;
+	if (dom)
+	{
+		for (auto i = dom->getChilds(); i; i++)
+		{ // TODO render elements backwards
+			Zeichnung* z = members->z(i->getAttributeValue("id"), i->getAttributeValue("id").getLength());
+			if (z)
+				z->doTastaturEreignis(te);
+		}
+	}
 }
 
 // Updated den Zeichenhintergrund
 //  tickVal: Die vergangene Zeit in Sekunden, die seit dem Letzten Aufruf dieser Funktion verstrichen ist
 //  return: 1, wenn das Bild neu gezeichnet werden muss. 0 sonnst
-bool UIMLView::tick( double tickVal )
+bool UIMLView::tick(double tickVal)
 {
-    if( dom )
-    {
-        for( auto i = dom->getChilds(); i; i++ )
-        { // TODO render elements backwards
-            Zeichnung *z = members->z( i->getAttributeValue( "id" ), i->getAttributeValue( "id" ).getLength() );
-            if( z )
-                rend |= z->tick( tickVal );
-        }
-    }
-    return ZeichnungHintergrund::tick( tickVal );
+	if (dom)
+	{
+		for (auto i = dom->getChilds(); i; i++)
+		{ // TODO render elements backwards
+			Zeichnung* z = members->z(i->getAttributeValue("id"), i->getAttributeValue("id").getLength());
+			if (z)
+				rend |= z->tick(tickVal);
+		}
+	}
+	return ZeichnungHintergrund::tick(tickVal);
 }
 
 // Zeichnet den Hintergrund eines Zeichnunges nach rObj
-void UIMLView::render( Bild &rObj )
+void UIMLView::render(Bild& rObj)
 {
-    ZeichnungHintergrund::render( rObj );
-    if( dom )
-    {
-        if( !rObj.setDrawOptions( pos.x + getRahmenBreite(), pos.y + getRahmenBreite(), gr.x + getRahmenBreite() * 2, gr.y + getRahmenBreite() * 2 ) )
-            return;
-        bool vSc = hatStyle( Style::VScroll ) && vertikalScrollBar;
-        bool hSc = hatStyle( Style::HScroll ) && horizontalScrollBar;
-        rObj.addScrollOffset( hSc ? horizontalScrollBar->getScroll() : 0, vSc ? vertikalScrollBar->getScroll() : 0 );
-        for( int i = dom->getChildCount() - 1; i >= 0; i-- )
-        { // TODO render elements backwards
-            XML::Element *e = dom->zChild( i );
-            Zeichnung *z = members->z( e->getAttributeValue( "id" ), e->getAttributeValue( "id" ).getLength() );
-            if( z )
-                z->render( rObj );
-        }
-        rObj.releaseDrawOptions();
-    }
+	ZeichnungHintergrund::render(rObj);
+	if (dom)
+	{
+		if (!rObj.setDrawOptions(pos.x + getRahmenBreite(), pos.y + getRahmenBreite(), gr.x + getRahmenBreite() * 2, gr.y + getRahmenBreite() * 2))
+			return;
+		bool vSc = hatStyle(Style::VScroll) && vertikalScrollBar;
+		bool hSc = hatStyle(Style::HScroll) && horizontalScrollBar;
+		rObj.addScrollOffset(hSc ? horizontalScrollBar->getScroll() : 0, vSc ? vertikalScrollBar->getScroll() : 0);
+		for (int i = dom->getChildCount() - 1; i >= 0; i--)
+		{ // TODO render elements backwards
+			XML::Element* e = dom->zChild(i);
+			Zeichnung* z = members->z(e->getAttributeValue("id"), e->getAttributeValue("id").getLength());
+			if (z)
+				z->render(rObj);
+		}
+		rObj.releaseDrawOptions();
+	}
 }
 
 // Gibt den Dom Tree ohne erhöhten reference counter zurück
 // Änderungen am Dom Tree sollten vermieden werden (nur änderungen von attributen einzelner elemente sind erlaubt)
-XML::Element *UIMLView::zDom() const
+XML::Element* UIMLView::zDom() const
 {
-    return dom;
+	return dom;
 }
 
 // Gibt den Dom Tree zurück
 // Änderungen am Dom Tree sollten vermieden werden (nur änderungen von attributen einzelner elemente sind erlaubt)
-XML::Element *UIMLView::getDom() const
+XML::Element* UIMLView::getDom() const
 {
-    return dom ? dynamic_cast<XML::Element *>(dom->getThis()) : 0;
+	return dom ? dynamic_cast<XML::Element*>(dom->getThis()) : 0;
 }

+ 17 - 0
Writer.cpp

@@ -0,0 +1,17 @@
+#include "Writer.h"
+
+using namespace Framework;
+
+OStreamWriter::OStreamWriter(std::ostream& out)
+	: out(out)
+{}
+
+void OStreamWriter::schreibe(const char* bytes, int len)
+{
+	out.write(bytes, (__int64)len);
+}
+
+bool OStreamWriter::istEnde() const
+{
+	return out.eof();
+}

+ 37 - 25
Writer.h

@@ -1,34 +1,46 @@
 #pragma once
 
 #include "Betriebssystem.h"
+#include <iostream>
 
 namespace Framework
 {
-    class Text;
+	class Text;
 
-    class StreamWriter
-    {
-    public:
-        //! Schreibt in die Resource
-        //! \param bytes Ein Array, der die Bytes enthält, welche in die Resource geschrieben werden soll
-        //! \param len Wie viele Bytes in die Resource geschrieben werden sollen
-        virtual void schreibe( const char *bytes, int len ) = 0;
-        //! Prüft, ob die Resource vollständig geschrieben wurde
-        //!  return 1, wenn die Resource vollständig geschrieben wurde. 0, sonst
-        virtual bool istEnde() const = 0;
-    };
+	class StreamWriter
+	{
+	public:
+		//! Schreibt in die Resource
+		//! \param bytes Ein Array, der die Bytes enthält, welche in die Resource geschrieben werden soll
+		//! \param len Wie viele Bytes in die Resource geschrieben werden sollen
+		virtual void schreibe(const char* bytes, int len) = 0;
+		//! Prüft, ob die Resource vollständig geschrieben wurde
+		//!  return 1, wenn die Resource vollständig geschrieben wurde. 0, sonst
+		virtual bool istEnde() const = 0;
+	};
 
-    class Writer : public StreamWriter
-    {
-    public:
-        //! Setzt die Position des Bytes, das als nächstes geschrieben werden soll
-        //! \param pos Der Index des Bytes
-        //! \param ende 1, wenn der Index vom ende der Resource zählt. 0, wenn der Index vom Beginn der Resource zählt
-        virtual void setSPosition( __int64 pos, bool ende ) = 0;
-        //! Gibt den Index des Bytes aus der Resource zurück, welches als nächstes geschrieben werden würde
-        //! return -1, falls ein Fehler aufgetreten ist. Sonst die Position des Schreibzeigers
-        virtual __int64 getSPosition() const = 0;
-        //! Gibt die Anzahl der zu schreibenden Bytes zurück
-        virtual __int64 getSize() const = 0;
-    };
+	class Writer : public StreamWriter
+	{
+	public:
+		//! Setzt die Position des Bytes, das als nächstes geschrieben werden soll
+		//! \param pos Der Index des Bytes
+		//! \param ende 1, wenn der Index vom ende der Resource zählt. 0, wenn der Index vom Beginn der Resource zählt
+		virtual void setSPosition(__int64 pos, bool ende) = 0;
+		//! Gibt den Index des Bytes aus der Resource zurück, welches als nächstes geschrieben werden würde
+		//! return -1, falls ein Fehler aufgetreten ist. Sonst die Position des Schreibzeigers
+		virtual __int64 getSPosition() const = 0;
+		//! Gibt die Anzahl der zu schreibenden Bytes zurück
+		virtual __int64 getSize() const = 0;
+	};
+
+	class OStreamWriter : public StreamWriter
+	{
+	private:
+		std::ostream& out;
+
+	public:
+		__declspec(dllexport) OStreamWriter(std::ostream& out);
+		__declspec(dllexport) void schreibe(const char* bytes, int len) override;
+		__declspec(dllexport) bool istEnde() const override;
+	};
 }

+ 504 - 486
XML.cpp

@@ -5,758 +5,776 @@ using namespace XML;
 
 // Erstellt ein XML Element
 //  string: entweder der name des Elements oder ein XML Text der geparsed werden soll
-Element::Element( Text string )
-    : Element( string, 0 )
+Element::Element(Text string)
+	: Element(string, 0)
 {}
 
 // Erstellt ein XML Element
 //  string: entweder der name des Elements oder ein XML Text der geparsed werden soll
 //  zParent: Ein Zeiger auf das eltern element (ohne erhöhten reference Counter)
-Element::Element( Text string, Element *zParent )
-    : ReferenceCounter()
-{
-    children = new RCArray< Element >();
-    attributes = new RCArray< Text >();
-    attributeValues = new RCArray< Text >();
-    text = new Text();
-    name = new Text();
-    string.removeWhitespaceAfter( 0 );
-    string.removeWhitespaceBefore( string.getLength() );
-    setText( string );
-    if( string[ 0 ] == '<' && string[ string.getLength() - 1 ] == '>' )
-    {
-        string.removeWhitespaceAfter( 1 );
-        string.removeWhitespaceBefore( string.getLength() - 1 );
-        int nameEnd = 0;
-        for( int i = 1; i < string.getLength(); i++ )
-        {
-            if( ( string[ i ] < 'a' || string[ i ] > 'z' ) &&
-                ( string[ i ] < 'A' || string[ i ] > 'Z' ) &&
-                ( string[ i ] < '0' || string[ i ] > '9' ) && string[ i ] != '-' )
-            {
-                nameEnd = i;
-                break;
-            }
-        }
-        name->setText( string.getTeilText( 1, nameEnd ) );
-        if( string.hatAt( string.getLength() - 1 - name->getLength(), name->getText() ) || string[ string.getLength() - 2 ] == '/' )
-        {
-            string.removeWhitespaceAfter( nameEnd );
-            // parse attributes
-            int start = nameEnd;
-            while( string[ nameEnd ] != '>' && string[ nameEnd ] != '/' )
-            {
-                for( int i = nameEnd + 1; i < string.getLength(); i++ )
-                {
-                    if( ( string[ i ] < 'a' || string[ i ] > 'z' ) &&
-                        ( string[ i ] < 'A' || string[ i ] > 'Z' ) &&
-                        ( string[ i ] < '0' || string[ i ] > '9' ) && string[ i ] != '-' )
-                    {
-                        nameEnd = i;
-                        break;
-                    }
-                }
-                Text *attrName = string.getTeilText( start, nameEnd );
-                string.removeWhitespaceAfter( nameEnd );
-                if( string[ nameEnd ] == '=' )
-                {
-                    string.removeWhitespaceAfter( nameEnd + 1 );
-                    Text value = "";
-                    if( string[ nameEnd + 1 ] == '"' )
-                    {
-                        bool esc = 0;
-                        start = nameEnd + 2;
-                        for( int i = nameEnd + 2; string[ i ]; i++ )
-                        {
-                            if( string[ i ] == '\\' )
-                                esc = !esc;
-                            else
-                            {
-                                if( string[ i ] == '"' && !esc )
-                                {
-                                    nameEnd = i + 1;
-                                    break;
-                                }
-                                esc = 0;
-                            }
-                        }
-                        value.setText( string.getTeilText( start, nameEnd - 1 ) );
-                        value.ersetzen( "\\\"", "\"" );
-                    }
-                    if( string[ nameEnd + 1 ] == '\'' )
-                    {
-                        bool esc = 0;
-                        start = nameEnd + 2;
-                        for( int i = nameEnd + 2; string[ i ]; i++ )
-                        {
-                            if( string[ i ] == '\\' )
-                                esc = !esc;
-                            else
-                            {
-                                if( string[ i ] == '\'' && !esc )
-                                {
-                                    nameEnd = i + 1;
-                                    break;
-                                }
-                                esc = 0;
-                            }
-                        }
-                        value.setText( string.getTeilText( start, nameEnd - 1 ) );
-                        value.ersetzen( "\\'", "'" );
-                    }
-                    setAttribute( attrName->getText(), value );
-                }
-                else
-                    setAttribute( attrName->getText(), "" );
-                attrName->release();
-                string.removeWhitespaceAfter( nameEnd );
-                start = nameEnd;
-            }
-            if( string[ string.getLength() - 2 ] != '/' )
-            {
-                string.removeWhitespaceBefore( string.getLength() - 1 - name->getLength() );
-                if( string[ string.getLength() - 2 - name->getLength() ] == '/' )
-                {
-                    string.removeWhitespaceBefore( string.getLength() - 2 - name->getLength() );
-                    if( string[ string.getLength() - 3 - name->getLength() ] == '<' )
-                    {
-                        text->setText( string.getTeilText( nameEnd + 1, string.getLength() - 3 - name->getLength() ) );
-                        // parse children
-                        text->removeWhitespaceAfter( 0 );
-                        text->removeWhitespaceBefore( text->getLength() );
-                        if( text->getText()[ 0 ] == '<' && text->getText()[ text->getLength() - 1 ] == '>' )
-                        {
-                            int start = 0;
-                            int lastStart = -1;
-                            while( start < text->getLength() )
-                            {
-                                if (lastStart == start) break;
-                                lastStart = start;
-                                bool esc = 0;
-                                bool inString1 = 0;
-                                bool inString2 = 0;
-                                int poc = 0;
-                                bool lastSlash = 0;
-                                bool lastOpen = 0;
-                                bool openSlash = 0;
-                                for( int i = 0; text->getText()[ i ]; i++ )
-                                {
-                                    switch( text->getText()[ i ] )
-                                    {
-                                    case '\\':
-                                        esc = !esc;
-                                        lastSlash = 0;
-                                        lastOpen = 0;
-                                        break;
-                                    case '"':
-                                        if( !esc && !inString2 )
-                                            inString1 = !inString1;
-                                        esc = 0;
-                                        lastSlash = 0;
-                                        lastOpen = 0;
-                                        break;
-                                    case '\'':
-                                        if( !esc && !inString1 )
-                                            inString2 = !inString2;
-                                        esc = 0;
-                                        lastSlash = 0;
-                                        lastOpen = 0;
-                                        break;
-                                    case '<':
-                                        if( !inString1 && !inString2 )
-                                            lastOpen = 1;
-                                        esc = 0;
-                                        lastSlash = 0;
-                                        break;
-                                    case '/':
-                                        lastSlash = 0;
-                                        if( !inString1 && !inString2 )
-                                        {
-                                            lastSlash = 1;
-                                            if( lastOpen )
-                                                openSlash = 1;
-                                        }
-                                        esc = 0;
-                                        lastOpen = 0;
-                                        break;
-                                    case '>':
-                                        if( !inString1 && !inString2 )
-                                        {
-                                            if( openSlash )
-                                                poc--;
-                                            else if( !lastSlash )
-                                                poc++;
-                                            if( poc == 0 )
-                                            {
-                                                Text *str = text->getTeilText( start, i + 1 );
-                                                addChild( new Element( str->getText(), this ) );
-                                                str->release();
-                                                start = i + 1;
-                                            }
-                                        }
-                                        esc = 0;
-                                        lastSlash = 0;
-                                        openSlash = 0;
-                                        break;
-                                    default:
-                                        esc = 0;
-                                        if( text->getText()[ i ] != ' ' && text->getText()[ i ] != '\t' && text->getText()[ i ] != '\r' && text->getText()[ i ] != '\n' )
-                                        {
-                                            lastSlash = 0;
-                                            lastOpen = 0;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            else
-                text->setText( "" );
-        }
-    }
-    parent = zParent;
+Element::Element(Text string, Element* zParent)
+	: ReferenceCounter()
+{
+	children = new RCArray< Element >();
+	attributes = new RCArray< Text >();
+	attributeValues = new RCArray< Text >();
+	text = new Text();
+	name = new Text();
+	string.removeWhitespaceAfter(0);
+	string.removeWhitespaceBefore(string.getLength());
+	setText(string);
+	if (string[0] == '<' && string[string.getLength() - 1] == '>')
+	{
+		string.removeWhitespaceAfter(1);
+		string.removeWhitespaceBefore(string.getLength() - 1);
+		int nameEnd = 0;
+		for (int i = 1; i < string.getLength(); i++)
+		{
+			if ((string[i] < 'a' || string[i] > 'z') &&
+				(string[i] < 'A' || string[i] > 'Z') &&
+				(string[i] < '0' || string[i] > '9') && string[i] != '-')
+			{
+				nameEnd = i;
+				break;
+			}
+		}
+		name->setText(string.getTeilText(1, nameEnd));
+		if (string.hatAt(string.getLength() - 1 - name->getLength(), name->getText()) || string[string.getLength() - 2] == '/')
+		{
+			string.removeWhitespaceAfter(nameEnd);
+			// parse attributes
+			int start = nameEnd;
+			while (string[nameEnd] != '>' && string[nameEnd] != '/')
+			{
+				for (int i = nameEnd + 1; i < string.getLength(); i++)
+				{
+					if ((string[i] < 'a' || string[i] > 'z') &&
+						(string[i] < 'A' || string[i] > 'Z') &&
+						(string[i] < '0' || string[i] > '9') && string[i] != '-')
+					{
+						nameEnd = i;
+						break;
+					}
+				}
+				Text* attrName = string.getTeilText(start, nameEnd);
+				string.removeWhitespaceAfter(nameEnd);
+				if (string[nameEnd] == '=')
+				{
+					string.removeWhitespaceAfter(nameEnd + 1);
+					Text value = "";
+					if (string[nameEnd + 1] == '"')
+					{
+						bool esc = 0;
+						start = nameEnd + 2;
+						for (int i = nameEnd + 2; string[i]; i++)
+						{
+							if (string[i] == '\\')
+								esc = !esc;
+							else
+							{
+								if (string[i] == '"' && !esc)
+								{
+									nameEnd = i + 1;
+									break;
+								}
+								esc = 0;
+							}
+						}
+						value.setText(string.getTeilText(start, nameEnd - 1));
+						value.ersetzen("\\\"", "\"");
+					}
+					if (string[nameEnd + 1] == '\'')
+					{
+						bool esc = 0;
+						start = nameEnd + 2;
+						for (int i = nameEnd + 2; string[i]; i++)
+						{
+							if (string[i] == '\\')
+								esc = !esc;
+							else
+							{
+								if (string[i] == '\'' && !esc)
+								{
+									nameEnd = i + 1;
+									break;
+								}
+								esc = 0;
+							}
+						}
+						value.setText(string.getTeilText(start, nameEnd - 1));
+						value.ersetzen("\\'", "'");
+					}
+					setAttribute(attrName->getText(), value);
+				}
+				else
+					setAttribute(attrName->getText(), "");
+				attrName->release();
+				string.removeWhitespaceAfter(nameEnd);
+				start = nameEnd;
+			}
+			if (string[string.getLength() - 2] != '/')
+			{
+				string.removeWhitespaceBefore(string.getLength() - 1 - name->getLength());
+				if (string[string.getLength() - 2 - name->getLength()] == '/')
+				{
+					string.removeWhitespaceBefore(string.getLength() - 2 - name->getLength());
+					if (string[string.getLength() - 3 - name->getLength()] == '<')
+					{
+						text->setText(string.getTeilText(nameEnd + 1, string.getLength() - 3 - name->getLength()));
+						// parse children
+						text->removeWhitespaceAfter(0);
+						text->removeWhitespaceBefore(text->getLength());
+						if (text->getText()[0] == '<' && text->getText()[text->getLength() - 1] == '>')
+						{
+							int start = 0;
+							int lastStart = -1;
+							while (start < text->getLength())
+							{
+								if (lastStart == start) break;
+								lastStart = start;
+								bool esc = 0;
+								bool inString1 = 0;
+								bool inString2 = 0;
+								int poc = 0;
+								bool lastSlash = 0;
+								bool lastOpen = 0;
+								bool openSlash = 0;
+								for (int i = 0; text->getText()[i]; i++)
+								{
+									switch (text->getText()[i])
+									{
+									case '\\':
+										esc = !esc;
+										lastSlash = 0;
+										lastOpen = 0;
+										break;
+									case '"':
+										if (!esc && !inString2)
+											inString1 = !inString1;
+										esc = 0;
+										lastSlash = 0;
+										lastOpen = 0;
+										break;
+									case '\'':
+										if (!esc && !inString1)
+											inString2 = !inString2;
+										esc = 0;
+										lastSlash = 0;
+										lastOpen = 0;
+										break;
+									case '<':
+										if (!inString1 && !inString2)
+											lastOpen = 1;
+										esc = 0;
+										lastSlash = 0;
+										break;
+									case '/':
+										lastSlash = 0;
+										if (!inString1 && !inString2)
+										{
+											lastSlash = 1;
+											if (lastOpen)
+												openSlash = 1;
+										}
+										esc = 0;
+										lastOpen = 0;
+										break;
+									case '>':
+										if (!inString1 && !inString2)
+										{
+											if (openSlash)
+												poc--;
+											else if (!lastSlash)
+												poc++;
+											if (poc == 0)
+											{
+												Text* str = text->getTeilText(start, i + 1);
+												addChild(new Element(str->getText(), this));
+												str->release();
+												start = i + 1;
+											}
+										}
+										esc = 0;
+										lastSlash = 0;
+										openSlash = 0;
+										break;
+									default:
+										esc = 0;
+										if (text->getText()[i] != ' ' && text->getText()[i] != '\t' && text->getText()[i] != '\r' && text->getText()[i] != '\n')
+										{
+											lastSlash = 0;
+											lastOpen = 0;
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+			else
+				text->setText("");
+		}
+	}
+	parent = zParent;
 }
 
 Element::~Element()
 {
-    children->release();
-    attributes->release();
-    attributeValues->release();
-    text->release();
-    name->release();
+	children->release();
+	attributes->release();
+	attributeValues->release();
+	text->release();
+	name->release();
 }
 
 // ändert ein attribut oder fügt eines hinzu
 //  attribut: Der Name des Attributes
 //  value: Der Wert des Attributes
-void Element::setAttribute( Text attribut, Text value )
+void Element::setAttribute(Text attribut, Text value)
 {
-    for( auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++ )
-    {
-        if( i->istGleich( attribut ) )
-        {
-            j->setText( value );
-            return;
-        }
-    }
-    attributes->add( new Text( attribut ) );
-    attributeValues->add( new Text( value ) );
+	for (auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++)
+	{
+		if (i->istGleich(attribut))
+		{
+			j->setText(value);
+			return;
+		}
+	}
+	attributes->add(new Text(attribut));
+	attributeValues->add(new Text(value));
 }
 
 // entfernt ein attribut
 //  attribut: Der Name des Attributes
-void Element::removeAttribute( Text attribut )
+void Element::removeAttribute(Text attribut)
 {
-    for( int i = 0; i < attributes->getEintragAnzahl(); i++ )
-    {
-        if( attributes->z( i )->istGleich( attribut ) )
-        {
-            attributes->remove( i );
-            attributeValues->remove( i );
-            i--;
-        }
-    }
+	for (int i = 0; i < attributes->getEintragAnzahl(); i++)
+	{
+		if (attributes->z(i)->istGleich(attribut))
+		{
+			attributes->remove(i);
+			attributeValues->remove(i);
+			i--;
+		}
+	}
 }
 
 // fügt ein child hinzu
 //  child: Das neue Child Element
-void Element::addChild( Element *child )
+void Element::addChild(Element* child)
 {
-    child->parent = this;
-    children->add( child );
+	child->parent = this;
+	children->add(child);
 }
 
 // fügt ein child hinzu
 //  child: Das neue Child Element
-void Element::addChildAtFront( Element *child )
+void Element::addChildAtFront(Element* child)
 {
-    child->parent = this;
-    children->add( child, 0 );
+	child->parent = this;
+	children->add(child, 0);
 }
 
 // entfernt ein child
 //  zChild: das zu entfernende Child
-void Element::removeChild( Element *child )
+void Element::removeChild(Element* child)
 {
-    for( int i = 0; i < children->getEintragAnzahl(); i++ )
-    {
-        if( children->z( i ) == child )
-        {
-            children->remove( i );
-            i--;
-        }
-    }
-    child->release();
+	for (int i = 0; i < children->getEintragAnzahl(); i++)
+	{
+		if (children->z(i) == child)
+		{
+			children->remove(i);
+			i--;
+		}
+	}
+	child->release();
 }
 
 // entfernt das i-te child
 //  i: der Index des childs (bei 0 beginnend)
-void Element::removeChild( int i )
+void Element::removeChild(int i)
 {
-    children->remove( i );
+	children->remove(i);
 }
 
 // entfernt alle childs
 void Element::removeAllChilds()
 {
-    children->leeren();
+	children->leeren();
 }
 
 // entfernt eine Liste mit childs
 //  childs: alle Childs die entfernt werden sollen
-void Element::removeChilds( RCArray<Element> *childs )
+void Element::removeChilds(RCArray<Element>* childs)
 {
-    for( auto i : *childs )
-        removeChild( dynamic_cast<XML::Element *>( i->getThis() ) );
-    childs->release();
+	for (auto i : *childs)
+		removeChild(dynamic_cast<XML::Element*>(i->getThis()));
+	childs->release();
 }
 
 // entfernt dieses Element vom Eltern element
 void Element::remove()
 {
-    if( parent )
-        parent->removeChild( dynamic_cast<XML::Element *>( getThis() ) );
+	if (parent)
+		parent->removeChild(dynamic_cast<XML::Element*>(getThis()));
 }
 
 // setzt den Text in dem Element falls es keine childs gibt
 //  text: dert Text
-void Element::setText( Text text )
+void Element::setText(Text text)
 {
-    this->text->setText( text );
+	this->text->setText(text);
 }
 
 // gibt den Text im Element zurück
 Text Element::getText() const
 {
-    return text->getText();
+	return text->getText();
 }
 
 // gibt die Anzahl der Childs zurück
 int Element::getChildCount() const
 {
-    return children->getEintragAnzahl();
+	return children->getEintragAnzahl();
 }
 
 // gibt das i-te child zurück
-Element *Element::getChild( int i ) const
+Element* Element::getChild(int i) const
 {
-    return children->get( i );
+	return children->get(i);
 }
 
 // gibt das i-te child zurück (ohne erhöhten reference Counter)
-Element *Element::zChild( int i ) const
+Element* Element::zChild(int i) const
 {
-    return children->z( i );
+	return children->z(i);
 }
 
 // gibt das parent element zurück
-Element *Element::getParent() const
+Element* Element::getParent() const
 {
-    return parent ? dynamic_cast<Element *>( parent->getThis() ) : 0;
+	return parent ? dynamic_cast<Element*>(parent->getThis()) : 0;
 }
 
 // gibt das parent element zurück (ohne erhöhten reference Counter)
-Element *Element::zParent() const
+Element* Element::zParent() const
 {
-    return parent;
+	return parent;
 }
 
 // gibt einen iterator zurück mit dem durch alle childs iteriert werden kann
-Iterator< Element * > Element::getChilds() const
+Iterator< Element* > Element::getChilds() const
 {
-    return children->begin();
+	return children->begin();
 }
 
 // gibt einen selector zurück der alle childs beinhaltet
 Editor Element::selectChildren() const
 {
-    return Editor( dynamic_cast<RCArray<XML::Element> *>( children->getThis() ) );
+	return Editor(dynamic_cast<RCArray<XML::Element> *>(children->getThis()));
 }
 
 // gibt eine Liste mit childs zurück, die einen bestimmten Namen haben
 //  name: der name der Childs
-Editor Element::selectChildsByName( Text name ) const
+Editor Element::selectChildsByName(Text name) const
 {
-    RCArray< Element > *tmp = new RCArray< Element >();
-    for( auto i : *children )
-    {
-        if( i->getName().istGleich( name ) )
-            tmp->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( tmp );
+	RCArray< Element >* tmp = new RCArray< Element >();
+	for (auto i : *children)
+	{
+		if (i->getName().istGleich(name))
+			tmp->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(tmp);
 }
 
 // gibt eine Liste mit childs zurück, die ein bestimmtes Attribut haben
 //  attribute: der name des Attributes
-Editor Element::selectChildsByAttribute( Text attribute ) const
+Editor Element::selectChildsByAttribute(Text attribute) const
 {
-    RCArray< Element > *tmp = new RCArray< Element >();
-    for( auto i : *children )
-    {
-        if( i->hasAttribute( attribute ) )
-            tmp->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( tmp );
+	RCArray< Element >* tmp = new RCArray< Element >();
+	for (auto i : *children)
+	{
+		if (i->hasAttribute(attribute))
+			tmp->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(tmp);
 }
 
 // gibt eine Liste mit childs zurück, die ein bestimmtes Attribut mit einem bestimmten wert haben
 //  attribute: der name des Attributes
 //  value: der Wert des Attributes
-Editor Element::selectChildsByAttribute( Text attribute, Text value ) const
+Editor Element::selectChildsByAttribute(Text attribute, Text value) const
 {
-    RCArray< Element > *tmp = new RCArray< Element >();
-    for( auto i : *children )
-    {
-        if( i->hasAttribute( attribute ) && i->getAttributeValue( attribute ).istGleich( value ) )
-            tmp->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( tmp );
+	RCArray< Element >* tmp = new RCArray< Element >();
+	for (auto i : *children)
+	{
+		if (i->hasAttribute(attribute) && i->getAttributeValue(attribute).istGleich(value))
+			tmp->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(tmp);
 }
 
 // gibt 1 zurück, falls ein Attribut Name existiert, 0 sonnst
-bool Element::hasAttribute( Text name ) const
+bool Element::hasAttribute(Text name) const
 {
-    for( auto i : *attributes )
-    {
-        if( i->istGleich( name ) )
-            return 1;
-    }
-    return 0;
+	for (auto i : *attributes)
+	{
+		if (i->istGleich(name))
+			return 1;
+	}
+	return 0;
 }
 
 // gibt die Anzahl der Attribute zurück
 int Element::getAttributeCount() const
 {
-    return attributes->getEintragAnzahl();
+	return attributes->getEintragAnzahl();
 }
 
 // gibt den Namen des i-ten Attributes zurück
-Text Element::getAttributeName( int i ) const
+Text Element::getAttributeName(int i) const
 {
-    return attributes->z( i )->getText();
+	return attributes->z(i)->getText();
 }
 
 // gibt den Wert des i-ten Attributes zurück
-Text Element::getAttributeValue( int i ) const
+Text Element::getAttributeValue(int i) const
 {
-    return attributeValues->z( i )->getText();
+	return attributeValues->z(i)->getText();
 }
 
 // gibt den Wert eines Attributes zurück
 //  attribut: Der Name des Attributes
-Text Element::getAttributeValue( Text attribut ) const
+Text Element::getAttributeValue(Text attribut) const
 {
-    for( auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++ )
-    {
-        if( i->istGleich( attribut ) )
-            return j->getText();
-    }
-    return "";
+	for (auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++)
+	{
+		if (i->istGleich(attribut))
+			return j->getText();
+	}
+	return "";
 }
 
 // gibt einen iterator zurück mit dem durch alle Attribut Namen iteriert werden kann
-Iterator< Text * > Element::getAttributeNames() const
+Iterator< Text* > Element::getAttributeNames() const
 {
-    return attributes->begin();
+	return attributes->begin();
 }
 
 // gibt einen iterator zurück mit dem durch alle Attribut Werte iteriert werden kann
-Iterator< Text * > Element::getAttributeValues() const
+Iterator< Text* > Element::getAttributeValues() const
 {
-    return attributeValues->begin();
+	return attributeValues->begin();
 }
 
 // gibt den Namen des Elementes zurück zurück
 Text Element::getName() const
 {
-    return name->getText();
+	return name->getText();
 }
 
 // erzeugt einen XML Text der dieses Element und alle childs beinhaltet
 Text Element::toString() const
 {
-    Text ret = "<";
-    ret += name->getText();
-    if( attributes->getEintragAnzahl() )
-        ret += " ";
-    for( auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++ )
-    {
-        ret += i->getText();
-        if( j->getLength() )
-        {
-            if( j->hat( '"' ) )
-            {
-                ret += "='";
-                Text txt = j->getText();
-                txt.ersetzen( "'", "\\'" );
-                ret += txt;
-                ret += "'";
-            }
-            else
-            {
-                ret += "=\"";
-                Text txt = j->getText();
-                txt.ersetzen( "\"", "\\\"" );
-                ret += txt;
-                ret += "\"";
-            }
-        }
-        if( i.hasNext() )
-            ret += " ";
-    }
-    if( children->getEintragAnzahl() || text->getLength() )
-    {
-        ret += ">";
-        if( children->getEintragAnzahl() )
-        {
-            for( auto i : *children )
-                ret += i->toString();
-        }
-        else
-            ret += text->getText();
-        ret += "</";
-        ret += name->getText();
-        ret += ">";
-    }
-    else
-        ret += "/>";
-    return ret;
+	Text ret = "<";
+	ret += name->getText();
+	if (attributes->getEintragAnzahl())
+		ret += " ";
+	for (auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++)
+	{
+		ret += i->getText();
+		if (j->getLength())
+		{
+			if (j->hat('"'))
+			{
+				ret += "='";
+				Text txt = j->getText();
+				txt.ersetzen("'", "\\'");
+				ret += txt;
+				ret += "'";
+			}
+			else
+			{
+				ret += "=\"";
+				Text txt = j->getText();
+				txt.ersetzen("\"", "\\\"");
+				ret += txt;
+				ret += "\"";
+			}
+		}
+		if (i.hasNext())
+			ret += " ";
+	}
+	if (children->getEintragAnzahl() || text->getLength())
+	{
+		ret += ">";
+		if (children->getEintragAnzahl())
+		{
+			for (auto i : *children)
+				ret += i->toString();
+		}
+		else
+			ret += text->getText();
+		ret += "</";
+		ret += name->getText();
+		ret += ">";
+	}
+	else
+		ret += "/>";
+	return ret;
 }
 
 // Erzeugt eine Kopie ohne referenzen auf dieses objekt
-Element *Element::dublicate() const
+Element* Element::dublicate() const
 {
-    return new Element( toString() );
+	return new Element(toString());
 }
 
 
 // Erzeugt einen neuen XML Editor mit einer Liste von Objekten die editiert werden sollen
-Editor::Editor( RCArray< Element > *elements )
-    : ReferenceCounter()
+Editor::Editor(RCArray< Element >* elements)
+	: ReferenceCounter()
 {
-    this->elements = new RCArray< Element >();
-    for( auto i : *elements )
-        this->elements->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    elements->release();
+	this->elements = new RCArray< Element >();
+	for (auto i : *elements)
+		this->elements->add(dynamic_cast<XML::Element*>(i->getThis()));
+	elements->release();
 }
 
-Editor::Editor( const Editor &e )
-    : Editor( dynamic_cast<RCArray<XML::Element> *>( e.elements->getThis() ) )
+Editor::Editor(const Editor& e)
+	: Editor(dynamic_cast<RCArray<XML::Element>*>(e.elements->getThis()))
 {}
 
 Editor::~Editor()
 {
-    elements->release();
+	elements->release();
 }
 
 // ändert ein attribut oder fügt eines hinzu (auf allen elementen in der Liste)
 //  attribut: Der Name des Attributes
 //  value: Der Wert des Attributes
-void Editor::setAttribute( Text attribut, Text value )
+void Editor::setAttribute(Text attribut, Text value)
 {
-    for( auto i : *elements )
-        i->setAttribute( attribut, value );
+	for (auto i : *elements)
+		i->setAttribute(attribut, value);
 }
 
 // entfernt ein attribut (auf allen elementen in der Liste)
 //  attribut: Der Name des Attributes
-void Editor::removeAttribute( Text attribut )
+void Editor::removeAttribute(Text attribut)
 {
-    for( auto i : *elements )
-        i->removeAttribute( attribut );
+	for (auto i : *elements)
+		i->removeAttribute(attribut);
 }
 
 // fügt ein child hinzu (auf allen elementen in der Liste)
 //  child: Das neue Child Element
-void Editor::addChild( Element *child )
+void Editor::addChild(Element* child)
 {
-    for( auto i : *elements )
-        i->addChild( child->dublicate() );
-    child->release();
+	for (auto i : *elements)
+		i->addChild(child->dublicate());
+	child->release();
 }
 
 // entfernt ein child (auf allen elementen in der Liste)
 //  zChild: das zu entfernende Child
-void Editor::removeChild( Element *child )
+void Editor::removeChild(Element* child)
 {
-    for( auto i : *elements )
-        i->removeChild( dynamic_cast<XML::Element *>( child->getThis() ) );
-    child->release();
+	for (auto i : *elements)
+		i->removeChild(dynamic_cast<XML::Element*>(child->getThis()));
+	child->release();
 }
 
 // entfernt das i-te child (auf allen elementen in der Liste)
 //  i: der Index des childs (bei 0 beginnend)
-void Editor::removeChild( int i )
+void Editor::removeChild(int i)
 {
-    for( auto j : *elements )
-        j->removeChild( i );
+	for (auto j : *elements)
+		j->removeChild(i);
 }
 
 // entfernt alle childs (auf allen elementen in der Liste)
 void Editor::removeAllChilds()
 {
-    for( auto i : *elements )
-        i->removeAllChilds();
+	for (auto i : *elements)
+		i->removeAllChilds();
 }
 
 // entfernt eine Liste mit childs (auf allen elementen in der Liste)
 //  childs: alle Childs die entfernt werden sollen
-void Editor::removeChilds( RCArray<Element> *childs )
+void Editor::removeChilds(RCArray<Element>* childs)
 {
-    for( auto i : *elements )
-        i->removeChilds( dynamic_cast<RCArray<XML::Element> *>( childs->getThis() ) );
-    childs->release();
+	for (auto i : *elements)
+		i->removeChilds(dynamic_cast<RCArray<XML::Element> *>(childs->getThis()));
+	childs->release();
 }
 
 // entfernt dieses Element vom Eltern element (auf allen elementen in der Liste)
 void Editor::remove()
 {
-    for( auto i : *elements )
-        i->remove();
+	for (auto i : *elements)
+		i->remove();
 }
 
 // setzt den Text in dem Element falls es keine childs gibt (auf allen elementen in der Liste)
 //  text: dert Text
-void Editor::setText( Text text )
+void Editor::setText(Text text)
 {
-    for( auto i : *elements )
-        i->setText( text );
+	for (auto i : *elements)
+		i->setText(text);
 }
 
 // Gibt ein Iterator durch alle Elemente zurück
-Iterator<Element *> Editor::getIterator()
+Iterator<Element*> Editor::begin()
 {
-    return elements->begin();
+	return elements->begin();
+}
+
+//! Gibt das ende des iterators zurück
+Iterator<Element*> Editor::end()
+{
+	return elements->end();
 }
 
 // gibt einen selector zurück der alle childs beinhaltet
 Editor Editor::selectChildren() const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        for( auto j = i->selectChildren().getIterator(); j; j++ )
-        {
-            list->add( dynamic_cast<XML::Element *>( j->getThis() ) );
-        }
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		for (auto j = i->selectChildren().begin(); j; j++)
+		{
+			list->add(dynamic_cast<XML::Element*>(j->getThis()));
+		}
+	}
+	return Editor(list);
 }
 
 // gibt einen selector zurück der alle parents beinhaltet
 Editor Editor::selectParents() const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        if( i->parent )
-            list->add( dynamic_cast<XML::Element *>( i->parent->getThis() ) );
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		if (i->parent)
+			list->add(dynamic_cast<XML::Element*>(i->parent->getThis()));
+	}
+	return Editor(list);
 }
 
 // gibt eine Liste mit elementen zurück, die einen bestimmten Namen haben
 //  name: der name der Childs
-Editor Editor::whereNameEquals( Text name ) const
+Editor Editor::whereNameEquals(Text name) const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        if( i->getName().istGleich( name ) )
-            list->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		if (i->getName().istGleich(name))
+			list->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(list);
 }
 
 // gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
 //  name: der name des childs
-Editor Editor::whereChildWithNameExists( Text name ) const
+Editor Editor::whereChildWithNameExists(Text name) const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        if( i->selectChildsByName( name ).elements->getEintragAnzahl() )
-            list->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		if (i->selectChildsByName(name).elements->getEintragAnzahl())
+			list->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(list);
 }
 
 // gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
 //  attribute: der name des attributes
-Editor Editor::whereChildWithAttributeExists( Text attribute ) const
+Editor Editor::whereChildWithAttributeExists(Text attribute) const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        if( i->selectChildsByAttribute( attribute ).elements->getEintragAnzahl() )
-            list->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		if (i->selectChildsByAttribute(attribute).elements->getEintragAnzahl())
+			list->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(list);
 }
 
 // gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
 //  attribute: der name des attributes
 //  value: der Wert des Attributes
-Editor Editor::whereChildWithAttributeExists( Text attribute, Text value ) const
+Editor Editor::whereChildWithAttributeExists(Text attribute, Text value) const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        if( i->selectChildsByAttribute( attribute, value ).elements->getEintragAnzahl() )
-            list->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		if (i->selectChildsByAttribute(attribute, value).elements->getEintragAnzahl())
+			list->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(list);
 }
 
 // gibt eine Liste mit elementen zurück, die ein bestimmtes Attribut haben
 //  attribute: der name des Attributes
-Editor Editor::whereAttributeExists( Text attribute ) const
+Editor Editor::whereAttributeExists(Text attribute) const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        if( i->hasAttribute( attribute ) )
-            list->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		if (i->hasAttribute(attribute))
+			list->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(list);
 }
 
 // gibt eine Liste mit elementen zurück, die ein bestimmtes Attribut mit einem bestimmten wert haben
 //  attribute: der name des Attributes
 //  value: der Wert des Attributes
-Editor Editor::whereAttributeEquals( Text attribute, Text value ) const
+Editor Editor::whereAttributeEquals(Text attribute, Text value) const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        if( i->hasAttribute( attribute ) && i->getAttributeValue( attribute ).istGleich( value ) )
-            list->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		if (i->hasAttribute(attribute) && i->getAttributeValue(attribute).istGleich(value))
+			list->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(list);
 }
 
 // Gibt einen Editor zurück welcher nurnoch die Elemente enthält die nicht in e sind
 //  e: Ein Editor mit elementen die nicht enthalten sein sollen
-Editor Editor::without( Editor e ) const
+Editor Editor::without(Editor e) const
 {
-    RCArray<Element> *list = new RCArray<Element>();
-    for( auto i : *elements )
-    {
-        bool found = 0;
-        for( auto j : *e.elements )
-            found |= i == j;
-        if( !found )
-            list->add( dynamic_cast<XML::Element *>( i->getThis() ) );
-    }
-    return Editor( list );
+	RCArray<Element>* list = new RCArray<Element>();
+	for (auto i : *elements)
+	{
+		bool found = 0;
+		for (auto j : *e.elements)
+			found |= i == j;
+		if (!found)
+			list->add(dynamic_cast<XML::Element*>(i->getThis()));
+	}
+	return Editor(list);
 }
 
 // Ruft eine funktion für jedes Element auf
 //  f: die funktion (nimmt als argument ein Element objekt ohne erhöhten reference Counter)
-void Editor::forEach( std::function< void( Element * ) > f ) const
+void Editor::forEach(std::function< void(Element*) > f) const
+{
+	for (auto i : *elements)
+		f(i);
+}
+
+//! gibt 1 zurück, wenn mindestens ein Element gefunden wurde
+bool Editor::exists() const
+{
+	return elements->getEintragAnzahl() > 0;
+}
+
+//! gibt die anzahl der ausgewählten elemente zurück
+int Editor::getSize() const
 {
-    for( auto i : *elements )
-        f( i );
+	return elements->getEintragAnzahl();
 }

+ 177 - 171
XML.h

@@ -6,181 +6,187 @@
 
 namespace Framework
 {
-    class Text;
+	class Text;
 
-    namespace XML
-    {
-        class Editor;
+	namespace XML
+	{
+		class Editor;
 
-        //! Ein XML element der Form \code <name attribut1 attribut2="value">text oder childs</name> \endcode
-        class Element : public virtual ReferenceCounter
-        {
-        private:
-            RCArray< Element > *children;
-            RCArray< Text > *attributes;
-            RCArray< Text > *attributeValues;
-            Text *name;
-            Text *text;
-            Element *parent;
+		//! Ein XML element der Form \code <name attribut1 attribut2="value">text oder childs</name> \endcode
+		class Element : public virtual ReferenceCounter
+		{
+		private:
+			RCArray< Element >* children;
+			RCArray< Text >* attributes;
+			RCArray< Text >* attributeValues;
+			Text* name;
+			Text* text;
+			Element* parent;
 
-        public:
-            //! Erstellt ein XML Element
-            //! \param string entweder der name des Elements oder ein XML Text der geparsed werden soll
-            DLLEXPORT Element( Text string );
-            //! Erstellt ein XML Element
-            //! \param string entweder der name des Elements oder ein XML Text der geparsed werden soll
-            //! \param zParent Ein Zeiger auf das eltern element (ohne erhöhten reference Counter)
-            DLLEXPORT Element( Text string, Element *zParent );
-            DLLEXPORT ~Element();
-            //! ändert ein attribut oder fügt eines hinzu
-            //! \param attribut Der Name des Attributes
-            //! \param value Der Wert des Attributes
-            DLLEXPORT void setAttribute( Text attribut, Text value );
-            //! entfernt ein attribut
-            //! \param attribut Der Name des Attributes
-            DLLEXPORT void removeAttribute( Text attribut );
-            //! fügt ein child hinzu
-            //! \param child Das neue Child Element
-            DLLEXPORT void addChild( Element *child );
-            //! fügt ein child hinzu
-            //! \param child Das neue Child Element
-            DLLEXPORT void addChildAtFront( Element *child );
-            //! entfernt ein child
-            //! \param zChild das zu entfernende Child
-            DLLEXPORT void removeChild( Element *child );
-            //! entfernt das i-te child
-            //! \param i der Index des childs (bei 0 beginnend)
-            DLLEXPORT void removeChild( int i );
-            //! entfernt alle childs
-            DLLEXPORT void removeAllChilds();
-            //! entfernt eine Liste mit childs
-            //! \param childs alle Childs die entfernt werden sollen
-            DLLEXPORT void removeChilds( RCArray<Element> *childs );
-            //! entfernt dieses Element vom Eltern element
-            DLLEXPORT void remove();
-            //! setzt den Text in dem Element falls es keine childs gibt
-            //! \param text dert Text
-            DLLEXPORT void setText( Text text );
-            //! gibt den Text im Element zurück
-            DLLEXPORT Text getText() const;
-            //! gibt die Anzahl der Childs zurück
-            DLLEXPORT int getChildCount() const;
-            //! gibt das i-te child zurück
-            DLLEXPORT Element *getChild( int i ) const;
-            //! gibt das i-te child zurück (ohne erhöhten reference Counter)
-            DLLEXPORT Element *zChild( int i ) const;
-            //! gibt das parent element zurück
-            DLLEXPORT Element *getParent() const;
-            //! gibt das parent element zurück (ohne erhöhten reference Counter)
-            DLLEXPORT Element *zParent() const;
-            //! gibt einen iterator zurück mit dem durch alle childs iteriert werden kann
-            DLLEXPORT Iterator< Element* > getChilds() const;
-            //! gibt einen selector zurück der alle childs beinhaltet
-            DLLEXPORT Editor selectChildren() const;
-            //! gibt eine Liste mit childs zurück, die einen bestimmten Namen haben
-            //! \param name der name der Childs
-            DLLEXPORT Editor selectChildsByName( Text name ) const;
-            //! gibt eine Liste mit childs zurück, die ein bestimmtes Attribut haben
-            //! \param attribute der name des Attributes
-            DLLEXPORT Editor selectChildsByAttribute( Text attribute ) const;
-            //! gibt eine Liste mit childs zurück, die ein bestimmtes Attribut mit einem bestimmten wert haben
-            //! \param attribute der name des Attributes
-            //! \param value der Wert des Attributes
-            DLLEXPORT Editor selectChildsByAttribute( Text attribute, Text value ) const;
-            //! gibt 1 zurück, falls ein Attribut Name existiert, 0 sonnst
-            DLLEXPORT bool hasAttribute( Text name ) const;
-            //! gibt die Anzahl der Attribute zurück
-            DLLEXPORT int getAttributeCount() const;
-            //! gibt den Namen des i-ten Attributes zurück
-            DLLEXPORT Text getAttributeName( int i ) const;
-            //! gibt den Wert des i-ten Attributes zurück
-            DLLEXPORT Text getAttributeValue( int i ) const;
-            //! gibt den Wert eines Attributes zurück
-            //! \param attribut Der Name des Attributes
-            DLLEXPORT Text getAttributeValue( Text attribut ) const;
-            //! gibt einen iterator zurück mit dem durch alle Attribut Namen iteriert werden kann
-            DLLEXPORT Iterator< Text* > getAttributeNames() const;
-            //! gibt einen iterator zurück mit dem durch alle Attribut Werte iteriert werden kann
-            DLLEXPORT Iterator< Text* > getAttributeValues() const;
-            //! gibt den Namen des Elementes zurück zurück
-            DLLEXPORT Text getName() const;
-            //! erzeugt einen XML Text der dieses Element und alle childs beinhaltet
-            DLLEXPORT Text toString() const;
-            //! Erzeugt eine Kopie ohne referenzen auf dieses objekt
-            DLLEXPORT Element *dublicate() const;
+		public:
+			//! Erstellt ein XML Element
+			//! \param string entweder der name des Elements oder ein XML Text der geparsed werden soll
+			DLLEXPORT Element(Text string);
+			//! Erstellt ein XML Element
+			//! \param string entweder der name des Elements oder ein XML Text der geparsed werden soll
+			//! \param zParent Ein Zeiger auf das eltern element (ohne erhöhten reference Counter)
+			DLLEXPORT Element(Text string, Element* zParent);
+			DLLEXPORT ~Element();
+			//! ändert ein attribut oder fügt eines hinzu
+			//! \param attribut Der Name des Attributes
+			//! \param value Der Wert des Attributes
+			DLLEXPORT void setAttribute(Text attribut, Text value);
+			//! entfernt ein attribut
+			//! \param attribut Der Name des Attributes
+			DLLEXPORT void removeAttribute(Text attribut);
+			//! fügt ein child hinzu
+			//! \param child Das neue Child Element
+			DLLEXPORT void addChild(Element* child);
+			//! fügt ein child hinzu
+			//! \param child Das neue Child Element
+			DLLEXPORT void addChildAtFront(Element* child);
+			//! entfernt ein child
+			//! \param zChild das zu entfernende Child
+			DLLEXPORT void removeChild(Element* child);
+			//! entfernt das i-te child
+			//! \param i der Index des childs (bei 0 beginnend)
+			DLLEXPORT void removeChild(int i);
+			//! entfernt alle childs
+			DLLEXPORT void removeAllChilds();
+			//! entfernt eine Liste mit childs
+			//! \param childs alle Childs die entfernt werden sollen
+			DLLEXPORT void removeChilds(RCArray<Element>* childs);
+			//! entfernt dieses Element vom Eltern element
+			DLLEXPORT void remove();
+			//! setzt den Text in dem Element falls es keine childs gibt
+			//! \param text dert Text
+			DLLEXPORT void setText(Text text);
+			//! gibt den Text im Element zurück
+			DLLEXPORT Text getText() const;
+			//! gibt die Anzahl der Childs zurück
+			DLLEXPORT int getChildCount() const;
+			//! gibt das i-te child zurück
+			DLLEXPORT Element* getChild(int i) const;
+			//! gibt das i-te child zurück (ohne erhöhten reference Counter)
+			DLLEXPORT Element* zChild(int i) const;
+			//! gibt das parent element zurück
+			DLLEXPORT Element* getParent() const;
+			//! gibt das parent element zurück (ohne erhöhten reference Counter)
+			DLLEXPORT Element* zParent() const;
+			//! gibt einen iterator zurück mit dem durch alle childs iteriert werden kann
+			DLLEXPORT Iterator< Element* > getChilds() const;
+			//! gibt einen selector zurück der alle childs beinhaltet
+			DLLEXPORT Editor selectChildren() const;
+			//! gibt eine Liste mit childs zurück, die einen bestimmten Namen haben
+			//! \param name der name der Childs
+			DLLEXPORT Editor selectChildsByName(Text name) const;
+			//! gibt eine Liste mit childs zurück, die ein bestimmtes Attribut haben
+			//! \param attribute der name des Attributes
+			DLLEXPORT Editor selectChildsByAttribute(Text attribute) const;
+			//! gibt eine Liste mit childs zurück, die ein bestimmtes Attribut mit einem bestimmten wert haben
+			//! \param attribute der name des Attributes
+			//! \param value der Wert des Attributes
+			DLLEXPORT Editor selectChildsByAttribute(Text attribute, Text value) const;
+			//! gibt 1 zurück, falls ein Attribut Name existiert, 0 sonnst
+			DLLEXPORT bool hasAttribute(Text name) const;
+			//! gibt die Anzahl der Attribute zurück
+			DLLEXPORT int getAttributeCount() const;
+			//! gibt den Namen des i-ten Attributes zurück
+			DLLEXPORT Text getAttributeName(int i) const;
+			//! gibt den Wert des i-ten Attributes zurück
+			DLLEXPORT Text getAttributeValue(int i) const;
+			//! gibt den Wert eines Attributes zurück
+			//! \param attribut Der Name des Attributes
+			DLLEXPORT Text getAttributeValue(Text attribut) const;
+			//! gibt einen iterator zurück mit dem durch alle Attribut Namen iteriert werden kann
+			DLLEXPORT Iterator< Text* > getAttributeNames() const;
+			//! gibt einen iterator zurück mit dem durch alle Attribut Werte iteriert werden kann
+			DLLEXPORT Iterator< Text* > getAttributeValues() const;
+			//! gibt den Namen des Elementes zurück zurück
+			DLLEXPORT Text getName() const;
+			//! erzeugt einen XML Text der dieses Element und alle childs beinhaltet
+			DLLEXPORT Text toString() const;
+			//! Erzeugt eine Kopie ohne referenzen auf dieses objekt
+			DLLEXPORT Element* dublicate() const;
 
-            friend Editor;
-        };
+			friend Editor;
+		};
 
-        //! Ein XML Editor der immer gleich mehrere Elemente editieren kann
-        class Editor : public virtual ReferenceCounter
-        {
-        private:
-            RCArray< Element > *elements;
+		//! Ein XML Editor der immer gleich mehrere Elemente editieren kann
+		class Editor : public virtual ReferenceCounter
+		{
+		private:
+			RCArray< Element >* elements;
 
-        public:
-            //! Erzeugt einen neuen XML Editor mit einer Liste von Objekten die editiert werden sollen
-            DLLEXPORT Editor( RCArray< Element > *elements );
-            DLLEXPORT Editor( const Editor &e );
-            DLLEXPORT ~Editor();
-            //! ändert ein attribut oder fügt eines hinzu (auf allen elementen in der Liste)
-            //! \param attribut Der Name des Attributes
-            //! \param value Der Wert des Attributes
-            DLLEXPORT void setAttribute( Text attribut, Text value );
-            //! entfernt ein attribut (auf allen elementen in der Liste)
-            //! \param attribut Der Name des Attributes
-            DLLEXPORT void removeAttribute( Text attribut );
-            //! fügt ein child hinzu (auf allen elementen in der Liste)
-            //! \param child Das neue Child Element
-            DLLEXPORT void addChild( Element *child );
-            //! entfernt ein child (auf allen elementen in der Liste)
-            //! \param zChild das zu entfernende Child
-            DLLEXPORT void removeChild( Element *child );
-            //! entfernt das i-te child (auf allen elementen in der Liste)
-            //! \param i der Index des childs (bei 0 beginnend)
-            DLLEXPORT void removeChild( int i );
-            //! entfernt alle childs (auf allen elementen in der Liste)
-            DLLEXPORT void removeAllChilds();
-            //! entfernt eine Liste mit childs (auf allen elementen in der Liste)
-            //! \param childs alle Childs die entfernt werden sollen
-            DLLEXPORT void removeChilds( RCArray<Element> *childs );
-            //! entfernt dieses Element vom Eltern element (auf allen elementen in der Liste)
-            DLLEXPORT void remove();
-            //! setzt den Text in dem Element falls es keine childs gibt (auf allen elementen in der Liste)
-            //! \param text dert Text
-            DLLEXPORT void setText( Text text );
-            //! Gibt ein Iterator durch alle Elemente zurück
-            DLLEXPORT Iterator<Element *> getIterator();
-            //! gibt einen selector zurück der alle childs beinhaltet
-            DLLEXPORT Editor selectChildren() const;
-            //! gibt einen selector zurück der alle parents beinhaltet
-            DLLEXPORT Editor selectParents() const;
-            //! gibt eine Liste mit elementen zurück, die einen bestimmten Namen haben
-            //! \param name der name der Childs
-            DLLEXPORT Editor whereNameEquals( Text name ) const;
-            //! gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
-            //! \param name der name des childs
-            DLLEXPORT Editor whereChildWithNameExists( Text name ) const;
-            //! gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
-            //! \param attribute der name des attributes
-            DLLEXPORT Editor whereChildWithAttributeExists( Text attribute ) const;
-            //! gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
-            //! \param attribute der name des attributes
-            //! \param value der Wert des Attributes
-            DLLEXPORT Editor whereChildWithAttributeExists( Text attribute, Text value ) const;
-            //! gibt eine Liste mit elementen zurück, die ein bestimmtes Attribut haben
-            //! \param attribute der name des Attributes
-            DLLEXPORT Editor whereAttributeExists( Text attribute ) const;
-            //! gibt eine Liste mit elementen zurück, die ein bestimmtes Attribut mit einem bestimmten wert haben
-            //! \param attribute der name des Attributes
-            //! \param value der Wert des Attributes
-            DLLEXPORT Editor whereAttributeEquals( Text attribute, Text value ) const;
-            //! Gibt einen Editor zurück welcher nurnoch die Elemente enthält die nicht in e sind
-            //! \param e Ein Editor mit elementen die nicht enthalten sein sollen
-            DLLEXPORT Editor without( Editor e ) const;
-            //! Ruft eine funktion für jedes Element auf (nimmt als argument ein Element objekt ohne erhöhten reference Counter)
-            //! \param f die funktion
-            DLLEXPORT void forEach( std::function< void( Element * ) > f ) const;
-        };
-    }
+		public:
+			//! Erzeugt einen neuen XML Editor mit einer Liste von Objekten die editiert werden sollen
+			DLLEXPORT Editor(RCArray< Element >* elements);
+			DLLEXPORT Editor(const Editor& e);
+			DLLEXPORT ~Editor();
+			//! ändert ein attribut oder fügt eines hinzu (auf allen elementen in der Liste)
+			//! \param attribut Der Name des Attributes
+			//! \param value Der Wert des Attributes
+			DLLEXPORT void setAttribute(Text attribut, Text value);
+			//! entfernt ein attribut (auf allen elementen in der Liste)
+			//! \param attribut Der Name des Attributes
+			DLLEXPORT void removeAttribute(Text attribut);
+			//! fügt ein child hinzu (auf allen elementen in der Liste)
+			//! \param child Das neue Child Element
+			DLLEXPORT void addChild(Element* child);
+			//! entfernt ein child (auf allen elementen in der Liste)
+			//! \param zChild das zu entfernende Child
+			DLLEXPORT void removeChild(Element* child);
+			//! entfernt das i-te child (auf allen elementen in der Liste)
+			//! \param i der Index des childs (bei 0 beginnend)
+			DLLEXPORT void removeChild(int i);
+			//! entfernt alle childs (auf allen elementen in der Liste)
+			DLLEXPORT void removeAllChilds();
+			//! entfernt eine Liste mit childs (auf allen elementen in der Liste)
+			//! \param childs alle Childs die entfernt werden sollen
+			DLLEXPORT void removeChilds(RCArray<Element>* childs);
+			//! entfernt dieses Element vom Eltern element (auf allen elementen in der Liste)
+			DLLEXPORT void remove();
+			//! setzt den Text in dem Element falls es keine childs gibt (auf allen elementen in der Liste)
+			//! \param text dert Text
+			DLLEXPORT void setText(Text text);
+			//! Gibt ein Iterator durch alle Elemente zurück
+			DLLEXPORT Iterator<Element*> begin();
+			//! Gibt das ende des iterators zurück
+			DLLEXPORT Iterator<Element*> end();
+			//! gibt einen selector zurück der alle childs beinhaltet
+			DLLEXPORT Editor selectChildren() const;
+			//! gibt einen selector zurück der alle parents beinhaltet
+			DLLEXPORT Editor selectParents() const;
+			//! gibt eine Liste mit elementen zurück, die einen bestimmten Namen haben
+			//! \param name der name der Childs
+			DLLEXPORT Editor whereNameEquals(Text name) const;
+			//! gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
+			//! \param name der name des childs
+			DLLEXPORT Editor whereChildWithNameExists(Text name) const;
+			//! gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
+			//! \param attribute der name des attributes
+			DLLEXPORT Editor whereChildWithAttributeExists(Text attribute) const;
+			//! gibt eine Liste mit elementen zurück, die ein bestimmtes child haben
+			//! \param attribute der name des attributes
+			//! \param value der Wert des Attributes
+			DLLEXPORT Editor whereChildWithAttributeExists(Text attribute, Text value) const;
+			//! gibt eine Liste mit elementen zurück, die ein bestimmtes Attribut haben
+			//! \param attribute der name des Attributes
+			DLLEXPORT Editor whereAttributeExists(Text attribute) const;
+			//! gibt eine Liste mit elementen zurück, die ein bestimmtes Attribut mit einem bestimmten wert haben
+			//! \param attribute der name des Attributes
+			//! \param value der Wert des Attributes
+			DLLEXPORT Editor whereAttributeEquals(Text attribute, Text value) const;
+			//! Gibt einen Editor zurück welcher nurnoch die Elemente enthält die nicht in e sind
+			//! \param e Ein Editor mit elementen die nicht enthalten sein sollen
+			DLLEXPORT Editor without(Editor e) const;
+			//! Ruft eine funktion für jedes Element auf (nimmt als argument ein Element objekt ohne erhöhten reference Counter)
+			//! \param f die funktion
+			DLLEXPORT void forEach(std::function< void(Element*) > f) const;
+			//! gibt 1 zurück, wenn mindestens ein Element gefunden wurde
+			DLLEXPORT bool exists() const;
+			//! gibt die anzahl der ausgewählten elemente zurück
+			DLLEXPORT int getSize() const;
+		};
+	}
 }

+ 103 - 102
main.h

@@ -26,43 +26,43 @@
 
 namespace Framework
 {
-    //! Speichert die dem Programm vom Betriebssystem beim Start übergebenen Parameter
-    struct Startparam
-    {
-        HINSTANCE hinst, hpinst;
-        LPSTR cmd;
-        int show;
-    };
-
-    //! Überschreibe diese Funktion. Sie wird vom Framework automatisch beim Start des Programmes aufgerufen
-    //! \param p Die Parameter, die dem Programm beim Start vom Betriebssystem übergeben wurden
-    int KSGStart Start( Startparam p );
+	//! Speichert die dem Programm vom Betriebssystem beim Start übergebenen Parameter
+	struct Startparam
+	{
+		HINSTANCE hinst, hpinst;
+		LPSTR cmd;
+		int show;
+	};
+
+	//! Überschreibe diese Funktion. Sie wird vom Framework automatisch beim Start des Programmes aufgerufen
+	//! \param p Die Parameter, die dem Programm beim Start vom Betriebssystem übergeben wurden
+	int KSGStart Start(Startparam p);
 }
 
-typedef BOOL( __stdcall* MINIDUMPWRITEDUMP )(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+typedef BOOL(__stdcall* MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
 
-void createMinidump( struct _EXCEPTION_POINTERS* apExceptionInfo )
+void createMinidump(struct _EXCEPTION_POINTERS* apExceptionInfo)
 {
-    HMODULE mhLib = ::LoadLibrary( "dbghelp.dll" );
-    MINIDUMPWRITEDUMP pDump = mhLib ? (MINIDUMPWRITEDUMP)::GetProcAddress( mhLib, "MiniDumpWriteDump" ) : 0;
+	HMODULE mhLib = ::LoadLibrary("dbghelp.dll");
+	MINIDUMPWRITEDUMP pDump = mhLib ? (MINIDUMPWRITEDUMP)::GetProcAddress(mhLib, "MiniDumpWriteDump") : 0;
 
-    HANDLE  hFile = ::CreateFile( "error_core_memory_dump.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
-                                  FILE_ATTRIBUTE_NORMAL, NULL );
+	HANDLE  hFile = ::CreateFile("error_core_memory_dump.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
+		FILE_ATTRIBUTE_NORMAL, NULL);
 
-    _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
-    ExInfo.ThreadId = ::GetCurrentThreadId();
-    ExInfo.ExceptionPointers = apExceptionInfo;
-    ExInfo.ClientPointers = FALSE;
+	_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
+	ExInfo.ThreadId = ::GetCurrentThreadId();
+	ExInfo.ExceptionPointers = apExceptionInfo;
+	ExInfo.ClientPointers = FALSE;
 
-    if( pDump )
-        pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL );
-    ::CloseHandle( hFile );
+	if (pDump)
+		pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL);
+	::CloseHandle(hFile);
 }
 
-LONG WINAPI unhandledHandler( struct _EXCEPTION_POINTERS* apExceptionInfo )
+LONG WINAPI unhandledHandler(struct _EXCEPTION_POINTERS* apExceptionInfo)
 {
-    createMinidump( apExceptionInfo );
-    return EXCEPTION_CONTINUE_SEARCH;
+	createMinidump(apExceptionInfo);
+	return EXCEPTION_CONTINUE_SEARCH;
 }
 
 #ifdef _DEBUG
@@ -70,92 +70,93 @@ template<typename TChar, typename TTraits>
 class OutputDebugStringBuf : public std::basic_stringbuf<TChar, TTraits>
 {
 public:
-    explicit OutputDebugStringBuf() : _buffer( 1 )
-    {
-        __super::setg( nullptr, nullptr, nullptr );
-        __super::setp( _buffer.data(), _buffer.data(), _buffer.data() + _buffer.size() );
-    }
-
-    ~OutputDebugStringBuf()
-    {}
-
-    static_assert(std::is_same<TChar, char>::value || std::is_same<TChar, wchar_t>::value, "OutputDebugStringBuf only supports char and wchar_t types");
-
-    int sync() try
-    {
-        MessageOutputer<TChar, TTraits>()(__super::pbase(), __super::pptr());
-        __super::setp( _buffer.data(), _buffer.data(), _buffer.data() + _buffer.size() );
-        return 0;
-    }
-    catch( ... )
-    {
-        return -1;
-    }
-
-    int overflow( int c = TTraits::eof() )
-    {
-        auto syncRet = sync();
-        if( c != TTraits::eof() )
-        {
-            _buffer[ 0 ] = c;
-            __super::setp( _buffer.data(), _buffer.data() + 1, _buffer.data() + _buffer.size() );
-        }
-        return syncRet == -1 ? TTraits::eof() : 0;
-    }
+	explicit OutputDebugStringBuf() : _buffer(1)
+	{
+		__super::setg(nullptr, nullptr, nullptr);
+		__super::setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
+	}
+
+	~OutputDebugStringBuf()
+	{}
+
+	static_assert(std::is_same<TChar, char>::value || std::is_same<TChar, wchar_t>::value, "OutputDebugStringBuf only supports char and wchar_t types");
+
+	int sync() try
+	{
+		MessageOutputer<TChar, TTraits>()(__super::pbase(), __super::pptr());
+		__super::setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
+		return 0;
+	}
+	catch (...)
+	{
+		return -1;
+	}
+
+	int overflow(int c = TTraits::eof())
+	{
+		auto syncRet = sync();
+		if (c != TTraits::eof())
+		{
+			_buffer[0] = c;
+			__super::setp(_buffer.data(), _buffer.data() + 1, _buffer.data() + _buffer.size());
+		}
+		return syncRet == -1 ? TTraits::eof() : 0;
+	}
 
 
 private:
-    std::vector<TChar>		_buffer;
-
-    template<typename TChar, typename TTraits>
-    struct MessageOutputer;
-
-    template<>
-    struct MessageOutputer<char, std::char_traits<char>>
-    {
-        template<typename TIterator>
-        void operator()( TIterator begin, TIterator end ) const
-        {
-            std::string s( begin, end );
-            OutputDebugStringA( s.c_str() );
-        }
-    };
-
-    template<>
-    struct MessageOutputer<wchar_t, std::char_traits<wchar_t>>
-    {
-        template<typename TIterator>
-        void operator()( TIterator begin, TIterator end ) const
-        {
-            std::wstring s( begin, end );
-            OutputDebugStringW( s.c_str() );
-        }
-    };
+	std::vector<TChar>		_buffer;
+
+	template<typename TChar, typename TTraits>
+	struct MessageOutputer;
+
+	template<>
+	struct MessageOutputer<char, std::char_traits<char>>
+	{
+		template<typename TIterator>
+		void operator()(TIterator begin, TIterator end) const
+		{
+			std::string s(begin, end);
+			OutputDebugStringA(s.c_str());
+		}
+	};
+
+	template<>
+	struct MessageOutputer<wchar_t, std::char_traits<wchar_t>>
+	{
+		template<typename TIterator>
+		void operator()(TIterator begin, TIterator end) const
+		{
+			std::wstring s(begin, end);
+			OutputDebugStringW(s.c_str());
+		}
+	};
 };
 #endif
 
-
-int WINAPI WinMain( _In_ HINSTANCE hinst, _In_opt_ HINSTANCE hpinst, _In_ LPSTR cmd, int _In_ show )
+#ifndef NO_MAIN
+int WINAPI WinMain(_In_ HINSTANCE hinst, _In_opt_ HINSTANCE hpinst, _In_ LPSTR cmd, int _In_ show)
 {
 #ifdef _DEBUG
-    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
-    OutputDebugStringBuf<char, std::char_traits<char>> charDebugOutput;
-    std::streambuf* buf = std::cout.rdbuf();
-    std::cout.rdbuf( &charDebugOutput );
+	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+	OutputDebugStringBuf<char, std::char_traits<char>> charDebugOutput;
+	std::streambuf* buf = std::cout.rdbuf();
+	std::cout.rdbuf(&charDebugOutput);
 #endif
-    SetUnhandledExceptionFilter( unhandledHandler );
-    Framework::initFramework( hinst );
-    Framework::Startparam stp;
-    stp.hinst = hinst;
-    stp.hpinst = hpinst;
-    stp.cmd = cmd;
-    stp.show = show;
-    int ret = Framework::Start( stp );
-    Framework::releaseFramework();
+	SetUnhandledExceptionFilter(unhandledHandler);
+	Framework::initFramework(hinst);
+	Framework::Startparam stp;
+	stp.hinst = hinst;
+	stp.hpinst = hpinst;
+	stp.cmd = cmd;
+	stp.show = show;
+	int ret = Framework::Start(stp);
+	Framework::releaseFramework();
 #ifdef _DEBUG
-    std::cout.rdbuf( buf );
+	std::cout.rdbuf(buf);
 #endif
-    return ret;
+	return ret;
 }
+#endif
 
 #endif