00001 #include <iostream>
00002
00003 #include "SDXValidator.h"
00004 #include "SDXDocument.h"
00005 #include "SDXDocumentBuilder.h"
00006 #include "SDXResourceReader.h"
00007
00008 using namespace std;
00009 using namespace SDX;
00010 using namespace SDX::Helpers;
00011
00012 Validator::Validator() :
00013 m_documentStructure(0)
00014 {
00015
00016 }
00017
00018 void Validator::setDocumentStructure(ResourceReader* resourceReader, bool deleteAfterReading){
00019 DocumentBuilder docBuilder;
00020
00021 resourceReader->setContentHandler(&docBuilder);
00022 if(resourceReader->read())
00023 m_documentStructure = docBuilder.getDocument();
00024
00025 if(deleteAfterReading)
00026 delete resourceReader;
00027 }
00028
00029 void Validator::setDocumentStructure(Document* doc){
00030 m_documentStructure = doc;
00031 }
00032
00033 bool Validator::validate(Document* docToValidate){
00034 InfoNode infoNode;
00035 infoNode.node = 0;
00036 m_infoNodes.push_back(infoNode);
00037
00038 const vector<Node*> childNodes(docToValidate->getChildren());
00039 for(unsigned int i = 0; i < childNodes.size(); ++i){
00040 Node* validationNode = m_documentStructure->getChild("Node", childNodes.at(i)->getName(), "name");
00041 if(validationNode){
00042 if(!validate(childNodes.at(i), validationNode))
00043 return false;
00044 }
00045 }
00046
00047 m_infoNodes.pop_back();
00048
00049 return true;
00050 }
00051
00052 string Validator::getError(){
00053 return m_error;
00054 }
00055
00056 void Validator::setError(string error){
00057 m_error = error;
00058 }
00059
00060 bool Validator::validate(Node* nodeToValidate, Node* validationNode){
00061 InfoNode infoNode;
00062 infoNode.node = nodeToValidate;
00063 m_infoNodes.push_back(infoNode);
00064
00065 vector<Attribute*> unnamedAttributes(nodeToValidate->getUnnamedAttributes());
00066 Node customValidationNode("");
00067 customValidationNode.setDeallocateContentOnDestruct(false);
00068
00069 if(!process(validationNode, &customValidationNode, &unnamedAttributes))
00070 return false;
00071
00072 const vector<Node*> childValidationNodes(customValidationNode.getChildren("Node"));
00073 for(unsigned int i = 0; i < childValidationNodes.size(); ++i){
00074 Node* curChildValidationNode = childValidationNodes.at(i);
00075
00076 string nodeName;
00077 if(!curChildValidationNode->getAttributeValue(&nodeName, "name") || nodeName.empty()){
00078 setError("No name set for node in validation document");
00079 return false;
00080 }
00081 if(nodeName.at(0) == '$'){
00082 nodeName = getPlaceholder(nodeName);
00083 if(nodeName.empty()){
00084 setError("Unknown placeholder in validation document");
00085 return false;
00086 }
00087 }
00088
00089 const vector<Node*> childNodes(nodeToValidate->getChildren(nodeName));
00090 if(childNodes.size() > 0){
00091 for(unsigned int j = 0; j < childNodes.size(); ++j){
00092 if(!validate(childNodes.at(j), curChildValidationNode))
00093 return false;
00094 }
00095 } else {
00096 setError("Missing node " + nodeName);
00097 return false;
00098 }
00099 }
00100
00101
00102 m_infoNodes.pop_back();
00103
00104 return true;
00105 }
00106
00107 bool Validator::validate(Attribute* attributeToValidate, Node* validationNode){
00108 string nodeType;
00109 if(!validationNode->getAttributeValue(&nodeType, "type")){
00110 setError("No type set for attribute in validation document");
00111 return false;
00112 }
00113
00114 if(nodeType == "String"){
00115 string nodeValue;
00116 if(!attributeToValidate->getValue(&nodeValue))
00117 return false;
00118
00119 vector<Node*> validValues(validationNode->getChildren("ValidValue"));
00120 if(validValues.size() > 0){
00121 bool validValueFound = false;
00122 for(unsigned int i = 0; i < validValues.size(); ++i){
00123 string validValue;
00124 if(!validValues.at(i)->getAttributeValue(&validValue)){
00125 setError("Missing attribute for ValidValue node in validation document");
00126 return false;
00127 }
00128
00129 if(nodeValue == validValue){
00130 validValueFound = true;
00131 break;
00132 }
00133 }
00134 if(!validValueFound){
00135 setError("Invalid value for attribute");
00136 return false;
00137 }
00138 }
00139 } else if(nodeType == "Int"){
00140 int nodeValue;
00141 if(!attributeToValidate->getValue(&nodeValue)){
00142 setError("Expected attribute to be of type int");
00143 return false;
00144 }
00145
00146 int nodeValueLimit;
00147 if(validationNode->getNodeAttributeValue(&nodeValueLimit, "MinValue") && nodeValue < nodeValueLimit){
00148 setError("Attribute value is less then minimum value");
00149 return false;
00150 }
00151 if(validationNode->getNodeAttributeValue(&nodeValueLimit, "MaxValue") && nodeValue > nodeValueLimit){
00152 setError("Attribute value is more then maximimum value");
00153 return false;
00154 }
00155 } else if(nodeType == "Float"){
00156 float nodeValue;
00157 if(!validationNode->getAttributeValue(&nodeValue))
00158 return false;
00159
00160 float nodeValueLimit;
00161 if(validationNode->getNodeAttributeValue(&nodeValueLimit, "MinValue") && nodeValue < nodeValueLimit){
00162 setError("Attribute value is less then minimum value");
00163 return false;
00164 }
00165 if(validationNode->getNodeAttributeValue(&nodeValueLimit, "MaxValue") && nodeValue > nodeValueLimit){
00166 setError("Attribute value is more then maximimum value");
00167 return false;
00168 }
00169 }
00170
00171 string storeInPlaceholder;
00172 if(validationNode->getNodeAttributeValue(&storeInPlaceholder, "StoreInPlaceholder"))
00173 attributeToValidate->getValue(&m_infoNodes.back().placeholders[storeInPlaceholder]);
00174
00175 return true;
00176 }
00177
00178 bool Validator::process(Node* validationNode, Node* customValidationNode, vector<Attribute*>* unnamedAttributes){
00179 vector<Node*> validationNodes(validationNode->getChildren());
00180 for(unsigned int i = 0; i < validationNodes.size(); ++i){
00181 Node* curValidationNode = validationNodes.at(i);
00182
00183 string curValidationNodeName(curValidationNode->getName());
00184 if(curValidationNodeName == "Attribute"){
00185 string attributeName;
00186 if(curValidationNode->getAttributeValue(&attributeName, "name")){
00187 if(attributeName.empty()){
00188 setError("Empty attribute name in validation document");
00189 return false;
00190 }
00191 if(attributeName.at(0) == '$'){
00192 attributeName = getPlaceholder(attributeName);
00193 if(attributeName.empty()){
00194 setError("Unknown placeholder " + attributeName);
00195 return false;
00196 }
00197 }
00198
00199 vector<Attribute*> namedAttributes(m_infoNodes.back().node->getAttributes(attributeName));
00200
00201 int occurenceLimit;
00202 if(curValidationNode->getNodeAttributeValue(&attributeName, "MinOccurences") && namedAttributes.size() < occurenceLimit){
00203 setError("Attribute " + attributeName + " occurs less then minimumum limit");
00204 return false;
00205 }
00206 if(curValidationNode->getNodeAttributeValue(&attributeName, "MaxOccurences") && namedAttributes.size() > occurenceLimit){
00207 setError("Attribute " + attributeName + " occurs more then maximum limit");
00208 return false;
00209 }
00210
00211 for(unsigned int j = 0; j < namedAttributes.size(); ++j){
00212 if(!validate(namedAttributes.at(j), curValidationNode))
00213 return false;
00214 }
00215 } else {
00216 if(unnamedAttributes->empty()){
00217 setError("Expected (another) unnamed attribute");
00218 return false;
00219 }
00220
00221 Attribute* unnamedAttribute = unnamedAttributes->front();
00222 if(!validate(unnamedAttribute, curValidationNode))
00223 return false;
00224 unnamedAttributes->erase(unnamedAttributes->begin());
00225 }
00226 } else if(curValidationNodeName == "If"){
00227 bool validIfFound = evaluateIf(curValidationNode);
00228 if(validIfFound)
00229 process(curValidationNode, customValidationNode, unnamedAttributes);
00230
00231 for(unsigned int j = i + 1; j < validationNodes.size(); ++j, ++i){
00232 if(validationNodes.at(j)->getName() == "Elseif"){
00233 if(!validIfFound && evaluateIf(validationNodes.at(j))){
00234 process(validationNodes.at(j), customValidationNode, unnamedAttributes);
00235 validIfFound = true;
00236 }
00237 } else if(validationNodes.at(j)->getName() == "Else") {
00238 if(!validIfFound){
00239 process(validationNodes.at(j), customValidationNode, unnamedAttributes);
00240 validIfFound = true;
00241 }
00242
00243 ++i;
00244 break;
00245 } else
00246 break;
00247 }
00248 } else if(curValidationNodeName == "Elseif" || curValidationNodeName == "Else") {
00249 setError("Unexpected " + curValidationNodeName + " node in validation document");
00250 return false;
00251 } else if(curValidationNodeName == "Node")
00252 customValidationNode->addChild(curValidationNode);
00253 }
00254
00255 return true;
00256 }
00257
00258 bool Validator::evaluateIf(SDX::Node* ifNode){
00259 vector<Attribute*> ifAttributes(ifNode->getAttributes());
00260
00261 if(ifAttributes.size() == 1){
00262 string attributeValue;
00263 ifAttributes.front()->getValue(&attributeValue);
00264
00265 if(attributeValue.size() == 0 || attributeValue.at(0) != '$')
00266 return false;
00267 else
00268 return !getPlaceholder(attributeValue).empty();
00269 } else if(ifAttributes.size() == 3){
00270 string lvalue, rvalue, operatorValue;
00271 ifAttributes.front()->getValue(&lvalue);
00272 ifAttributes.back()->getValue(&rvalue);
00273
00274 Attribute* operatorAttribute = ifAttributes.at(1);
00275 operatorAttribute->getValue(&operatorValue);
00276
00277 if(!operatorAttribute->isNamedAttribute() && operatorValue == "=")
00278 return (lvalue.at(0) == '$' ? getPlaceholder(lvalue) : lvalue) == (rvalue.at(0) == '$' ? getPlaceholder(rvalue) : rvalue);
00279 else if(operatorAttribute->isNamedAttribute() && operatorValue.empty() && operatorAttribute->getName() == "!")
00280 return (lvalue.at(0) == '$' ? getPlaceholder(lvalue) : lvalue) != (rvalue.at(0) == '$' ? getPlaceholder(rvalue) : rvalue);
00281 else
00282 return false;
00283 }
00284
00285 return false;
00286 }
00287
00288 string Validator::getPlaceholder(string name){
00289 if(name.empty())
00290 return "";
00291 if(name.at(0) == '$')
00292 name.erase(0, 1);
00293
00294 string retVal;
00295 for(int i = m_infoNodes.size() - 1; i >= 0; --i){
00296 if(m_infoNodes.at(i).placeholders.count(name) > 0){
00297 retVal = m_infoNodes.at(i).placeholders[name];
00298 break;
00299 }
00300 }
00301 return retVal;
00302 }