//
// $Id: DOMOvalXMLAnalyzer.cpp,v 1.8 2004/10/19 17:03:21 bakerj Exp $
//
//************************** Property of the MITRE Corporation ***************************//
//
// Copyright (c) 2003 - The MITRE Corporation
//
// This file is part of the Query-based Network Assessment project.
//
// The Query-based Network Assessment is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License.
//
// The Query-based Network Assessment is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with the
// Query-based Network Assessment; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//****************************************************************************************//

#include "DOMOvalXMLAnalyzer.h"

//****************************************************************************************//
//								DOMOvalXMLAnalyzer Class								  //
//****************************************************************************************//

DOMOvalXMLAnalyzer::DOMOvalXMLAnalyzer(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *oval, 
									   XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *data, 
									   DOMProcessor *processorIn, bool useConfig)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Init the DOMOvalXMLAnalyzer
	//	Throw an exception if there is an error.
	// -----------------------------------------------------------------------

    try 
	{
        XMLPlatformUtils::Initialize();
    }
    catch (const XMLException& toCatch) 
	{
        string errMsg = "Error:  An error occured durring initialization of the xml utilities:\n";
        errMsg.append(DOMCommon::ToString(toCatch.getMessage()));
		errMsg.append("\n");

		throw DOMOvalXMLAnalyzerException(errMsg);
    }

	//	Set the oval file
	if(oval == NULL)
		throw DOMOvalXMLAnalyzerException("Error: A NULL oval document has been selected for analysis.");
	else
		ovalDoc = oval;

	//	Set the data file
	if(data == NULL)
		throw DOMOvalXMLAnalyzerException("Error: A NULL data document has been selected for analysis.");
	else
		dataDoc = data; 

	//	Determine what family to process.based on data file
	SetOSFamily();

	//	Create a new DOMOvalResultXML object
	myResultXML = new DOMOvalResultXML(processorIn, osFamily);

	//	Set the useConfiguration flag
	useConfiguration = useConfig;
	
}

DOMOvalXMLAnalyzer::~DOMOvalXMLAnalyzer()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Clean up after the DOMOvalXMLAnalyzer
	// -----------------------------------------------------------------------

	XMLPlatformUtils::Terminate();
}

// ***************************************************************************************	//
//								Public members												//
// ***************************************************************************************	//

XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* DOMOvalXMLAnalyzer::Run()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Run the analysis
	// -----------------------------------------------------------------------

	//	Get the host name and ip address
	string hostname = DOMCommon::GetDataNodeValue(DOMCommon::FindNode(dataDoc, "host_name"));
	string ip = DOMCommon::GetDataNodeValue(DOMCommon::FindNode(dataDoc, "ip_address"));

	if(hostname.compare("") == 0)
		hostname = "NOT SPECIFIED";

	if(ip.compare("") == 0)
		ip = "NOT SPECIFIED";

	//	Display a message with the host name and the ip address
	cout << "    Performing analysis on:" << endl;
	cout << "    Host Name : " << hostname << endl;
	cout << "    IP Address: " << ip << "\n" <<endl;
	Log::WriteLog("    Performing analysis on:\n");
	Log::WriteLog("    Host Name : " + hostname + "\n");
	Log::WriteLog("    IP Address: " + ip + "\n\n");


	//	Get the oval timestamp value
	string ovalTimeStamp = DOMCommon::GetAttributeByName(ovalDoc->getDocumentElement(), "oval:timeStamp"); 

	//	Add the time stamps to the result file
	myResultXML->AddTimeStamps((DOMElement*)DOMCommon::FindNode(dataDoc, "time_stamp"), ovalTimeStamp);

	//	Add the host name and ip address to the result file
	myResultXML->AddHostInfo(hostname, ip);

	//	Start the evaluation
	EvaluateDefinitions();

	//	Get the result document and return it.
	return (myResultXML->GetResultFile());
}

// ***************************************************************************************	//
//								Private members												//
// ***************************************************************************************	//
int DOMOvalXMLAnalyzer::Compare(DOMNode *ovalNode, DOMNode *dataNode)
								//string op, string datatype, string defValue, 
								//string dataValue, bool existanceFlag)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the oval node to the data node using the operator specified 
	//	on the oval node. Preform the comparison by calling the correct datatype 
	//	specific comparison function. Handle existance tests. Note that with
	//	every comparison there is an implicit existance test except for when the
	//	specified operator is "does not exist"
	//
	//	Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	int result = UNKNOWN_TEST_RESULT;

	//	Get data node's exists flag
	bool existanceFlag = false;
	string tmpExists = DOMCommon::GetAttributeByName(dataNode, "exists");
	if(tmpExists.compare("true") == 0)
		existanceFlag = true;
	else if(tmpExists.compare("false") == 0)
		existanceFlag = false;
	else if(tmpExists.compare("") == 0)
		existanceFlag = true;			
	else
	{
		string errMsg = "Error: Invalid value for exists attribute on a element in the system configuration document.\n\tFound: ";
		errMsg.append(tmpExists);
		throw DOMOvalXMLAnalyzerException(errMsg);
	}

	//	Get the operator on the oval node
	//	Default to exists
	string op = DOMCommon::GetAttributeByName(ovalNode, "operator");
	if(op.compare("") == 0)
		op = "exists";

	//	Preform existance test
	if(op.compare("exists") == 0)
	{	
		//	check existance flag
		if(existanceFlag)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;

	}else if(op.compare("does not exist") == 0)
	{	
		//	check if data exists
		if(existanceFlag)
			result = FALSE_TEST_RESULT;				
		else
			result = TRUE_TEST_RESULT;
		
	}else if(!existanceFlag)
	{	
		//	The implicit check for existance
		//	any operator other than a check for existance and the data doesn't exist
		result = FALSE_TEST_RESULT;
	
	}else
	{
		//	Get the data type on the oval node
		//	Defualt to string
		string datatype = DOMCommon::GetAttributeByName(ovalNode, "datatype");
		if(datatype.compare("") == 0)
			datatype = "string";

		//	Call the correct data type specific comparison fuction to get the result
		if(datatype.compare("version") == 0)
		{
			result = CompareVersion(ovalNode, dataNode);
		
		}else
		{
			//	Get the value of the oval node
			string defValue = DOMCommon::GetDataNodeValue(ovalNode);

			//	Get the value of the data node
			string dataValue = DOMCommon::GetDataNodeValue(dataNode);

			//	Make call for remaining datatypes
			if(datatype.compare("binary") == 0)
				result = CompareBinary(op, defValue, dataValue);
			else if(datatype.compare("float") == 0)
				result = CompareFloat(op, defValue, dataValue);
			else if(datatype.compare("int") == 0)
				result = CompareInt(op, defValue, dataValue);
			else if(datatype.compare("string") == 0)
				result = CompareString(op, defValue, dataValue);
		}
	}

	return result;
}


int DOMOvalXMLAnalyzer::CompareBinary(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//
	//	Currently only support equals and not equal
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	int result = UNKNOWN_TEST_RESULT;

	//	Check to ensure only 1's and 0's in the string
	REGEX *myMatcher = new REGEX();
	if(!myMatcher->IsMatch("^[1|0]+$", dataValue.c_str()))
		throw DOMOvalXMLAnalyzerException("Error: Non binary data found when data type indicated binary data."); 

	delete myMatcher;

	// Process accepted operators
	if(op.compare("equals") == 0 || op.compare("not equal") == 0)
	{
		result = CompareString(op, defValue, dataValue);

	}else
	{
		//	Unsupported operator
		throw DOMOvalXMLAnalyzerException("Error: Unsupported operator specified for binary data: " + op);
	}

	return result;
}

int DOMOvalXMLAnalyzer::CompareFloat(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//	Only handle comparisons that are logical for a float.
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	int result = UNKNOWN_TEST_RESULT;

	// convert the two strings to doubles
	double fltDefValue = atof(defValue.c_str());
	double fltDataValue = atof(dataValue.c_str());

	//	Based on the operator preform the comparison
	if(op.compare("equals") == 0 )
	{
		if(fltDefValue == fltDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("not equal") == 0 )
	{
		if(fltDefValue != fltDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("greater than") == 0 )
	{
		if(fltDefValue < fltDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("less than") == 0 )
	{
		if(fltDefValue > fltDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("greater than or equal") == 0 )
	{
		if(fltDefValue <= fltDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("less than or equal") == 0 )
	{
		if(fltDefValue >= fltDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("pattern match") == 0  || op.compare("bitwise and") == 0 ||
			 op.compare("bitwise or") == 0)
	{
		//	Unsupported operator
		throw DOMOvalXMLAnalyzerException("Error: Unsupported operator specified: " + op);	

	}else 
	{
		//	Unknown operator
		throw DOMOvalXMLAnalyzerException("Error: Unknown operator specified: " + op);	
	}

	return result;
}

int DOMOvalXMLAnalyzer::CompareInt(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//	Only handle compairisons that are logical for an int
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	int result = UNKNOWN_TEST_RESULT;

	// Convert the two strings to ints
	int intDefValue = atoi(defValue.c_str());
	int intDataValue = atoi(dataValue.c_str());

	//	Based on the operator preform the comparison
	if(op.compare("equals") == 0 )
	{
		if(intDefValue == intDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("not equal") == 0 )
	{
		if(intDefValue != intDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("greater than") == 0 )
	{
		if(intDefValue < intDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("less than") == 0 )
	{
		if(intDefValue > intDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("greater than or equal") == 0 )
	{
		if(intDefValue <= intDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("less than or equal") == 0 )
	{
		if(intDefValue >= intDataValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("pattern match") == 0)
	{		
		//	Unsupported operator
		throw DOMOvalXMLAnalyzerException("Error: Unsupported operator specified: " + op);	
		
	}else if(op.compare("bitwise and") == 0)
	{
		if((intDataValue & intDefValue) == intDefValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;		
	
	}else if(op.compare("bitwise or") == 0)
	{
		if((intDataValue | intDefValue) == intDefValue)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;	

	}else 
	{
		//	Unknown operator
		throw DOMOvalXMLAnalyzerException("Error: Unknown operator specified: " + op);	
	}

	return result;

}

int DOMOvalXMLAnalyzer::CompareString(string op, string defValue, string dataValue)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//	Only handle compairisons that are logical for a string
	//
	// -----------------------------------------------------------------------
	
	//	Defualt to unknown result
	int result = UNKNOWN_TEST_RESULT;

	//	Based on the operator preform the comparison
	if(op.compare("equals") == 0)
	{
		if(defValue.compare(dataValue) == 0)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("not equal") == 0)
	{
		if(defValue.compare(dataValue) != 0)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("greater than or equal") == 0)
	{
		if(defValue.compare(dataValue) >= 0)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("less than or equal") == 0)
	{
		if(defValue.compare(dataValue) <= 0)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("greater than") == 0)
	{
		if(defValue.compare(dataValue) > 0)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("less than") == 0)
	{
		if(defValue.compare(dataValue) < 0)
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;
	}else if(op.compare("pattern match") == 0)
	{
		REGEX *myMatcher = new REGEX();
		
		if(myMatcher->IsMatch(defValue.c_str(), dataValue.c_str()))
			result = TRUE_TEST_RESULT;
		else
			result = FALSE_TEST_RESULT;

		delete myMatcher;

	}else if(op.compare("bitwise and") == 0 || op.compare("bitwise or") == 0)
	{
		//	Unsupported operator
		throw DOMOvalXMLAnalyzerException("Error: Unsupported operator specified: " + op);	

	}else 
	{
		//	Unknown operator
		throw DOMOvalXMLAnalyzerException("Error: Unsupported operator specified: " + op);	
	}

	return result;
}

int DOMOvalXMLAnalyzer::CompareVersion(DOMNode *ovalNode, DOMNode *dataNode)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Compare the definition value to the data value using the specified 
	//	operator. Return either UNKNOWN_TEST_RESULT, FALSE_TEST_RESULT, or
	//	TRUE_TEST_RESULT. 
	//	
	// -----------------------------------------------------------------------

	//	Defualt to unknown result
	int result = UNKNOWN_TEST_RESULT;

	//	Ensure that the data type on the oval node is version
	string datatype = DOMCommon::GetAttributeByName(ovalNode, "datatype");
	if(datatype.compare("version") != 0)
		throw DOMOvalXMLAnalyzerException("Error: CompareVersion() only compares elements with a data type of version. Found: " + datatype);		
	
	//	Get the operator from the oval node
	string op = DOMCommon::GetAttributeByName(ovalNode, "operator");
	if(op.compare("") == 0)
		op = "exists";

	//	Get the value of the major, minor, private, and built elements
	//	for both the oval node and the data node
	DOMNode *tmpVersionComponent = NULL;
	int ovalVersion[4];
	int dataVersion[4];

	//	Get the oval version componets
	tmpVersionComponent = DOMCommon::FindNode(ovalNode, "major");
	ovalVersion[0] = atoi(DOMCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = DOMCommon::FindNode(ovalNode, "minor");
	ovalVersion[1] = atoi(DOMCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = DOMCommon::FindNode(ovalNode, "build");
	ovalVersion[2] = atoi(DOMCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = DOMCommon::FindNode(ovalNode, "private");
	ovalVersion[3] = atoi(DOMCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	
	//	Get the data version componets
	tmpVersionComponent = DOMCommon::FindNode(dataNode, "major");
	dataVersion[0] = atoi(DOMCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = DOMCommon::FindNode(dataNode, "minor");
	dataVersion[1] = atoi(DOMCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = DOMCommon::FindNode(dataNode, "build");
	dataVersion[2] = atoi(DOMCommon::GetDataNodeValue(tmpVersionComponent).c_str());
	tmpVersionComponent = DOMCommon::FindNode(dataNode, "private");
	dataVersion[3] = atoi(DOMCommon::GetDataNodeValue(tmpVersionComponent).c_str());	

	
	//	Based on the operator preform the comparison
	if(op.compare("equals") == 0)
	{
		if( ovalVersion[0] == dataVersion[0] && 
			ovalVersion[1] == dataVersion[1] &&
			ovalVersion[2] == dataVersion[2] &&
			ovalVersion[3] == dataVersion[3])
		{
			result = TRUE_TEST_RESULT;

		}else
			result = FALSE_TEST_RESULT;

	}else if(op.compare("not equal") == 0)
	{
		if( ovalVersion[0] != dataVersion[0] || 
			ovalVersion[1] != dataVersion[1] ||
			ovalVersion[2] != dataVersion[2] ||
			ovalVersion[3] != dataVersion[3])
		{
			result = TRUE_TEST_RESULT;

		}else
			result = FALSE_TEST_RESULT;

	}else if(op.compare("greater than or equal") == 0)
	{
		if( (ovalVersion[0] < dataVersion[0]) || 
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] < dataVersion[1]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] < dataVersion[2]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] == dataVersion[2] && ovalVersion[3] <= dataVersion[3]))
		{
			result = TRUE_TEST_RESULT;

		}else
			result = FALSE_TEST_RESULT;

	}else if(op.compare("less than or equal") == 0)
	{
		if( (ovalVersion[0] > dataVersion[0]) || 
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] > dataVersion[1]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] > dataVersion[2]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] == dataVersion[2] && ovalVersion[3] >= dataVersion[3]))
		{
			result = TRUE_TEST_RESULT;

		}else
			result = FALSE_TEST_RESULT;

	}else if(op.compare("greater than") == 0)
	{
		if( (ovalVersion[0] < dataVersion[0]) || 
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] < dataVersion[1]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] < dataVersion[2]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] == dataVersion[2] && ovalVersion[3] < dataVersion[3]))
		{
			result = TRUE_TEST_RESULT;

		}else
			result = FALSE_TEST_RESULT;

	}else if(op.compare("less than") == 0)
	{
		if( (ovalVersion[0] > dataVersion[0]) || 
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] > dataVersion[1]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] > dataVersion[2]) ||
			(ovalVersion[0] == dataVersion[0] && ovalVersion[1] == dataVersion[1] && ovalVersion[2] == dataVersion[2] && ovalVersion[3] > dataVersion[3]))
		{
			result = TRUE_TEST_RESULT;

		}else
			result = FALSE_TEST_RESULT;

	}else if(op.compare("bitwise and") == 0 || op.compare("bitwise or") == 0 || op.compare("pattern match") == 0)
	{
		//	Unsupported operator
		throw DOMOvalXMLAnalyzerException("Error: Unsupported operator specified: " + op);	

	}else 
	{
		//	Unknown operator
		throw DOMOvalXMLAnalyzerException("Error: Unknown operator specified: " + op);	
	}

	return result;
}

int DOMOvalXMLAnalyzer::ComputeSimpleTestResult(DOMNode *ovalNode, DOMNode *dataNode, string parentOp, bool useParentOp, string parentDataType, bool useParentDataType)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the result value of a test between two children of a test element.
	//	This will be done recursively since a test element's child may be specified that
	//	has child nodes and those child node need to be processed.
	//	Only nodes of type ELEMENT_NODE will be processed all others will result
	//	in an error.
	//
	//	6-16-2004: may no longer need the parent operator and dataype. Only
	//	possibility is in the windows path element in a file test
	// -----------------------------------------------------------------------

	//	Oval node should never be NULL 
	if(ovalNode == NULL)
	{
		string errMsg = "Error: An invalid node was passed to DOMOvalXMLAnalyzer::ComputeSimpleTestResult.\n";
		errMsg.append("The oval node is NULL");
		throw DOMOvalXMLAnalyzerException(errMsg);
	}

	//	If the data node is NULL the result is always UNKNOWN_TEST_RESULT
	if(dataNode == NULL)
		return UNKNOWN_TEST_RESULT;

	//	Check that both the oval and the data are the correct type of node
	if(ovalNode->getNodeType() != DOMNode::ELEMENT_NODE)
	{
		string errMsg = "Error: An invalid oval node was passed to DOMOvalXMLAnalyzer::ComputeSimpleTestResult.\n";
		errMsg.append("Expected DOMNode::ELEMENT_NODE");
		throw DOMOvalXMLAnalyzerException(errMsg);
	}
	if(dataNode->getNodeType() != DOMNode::ELEMENT_NODE)
	{
		string errMsg = "Error: An invalid data node was passed to DOMOvalXMLAnalyzer::ComputeSimpleTestResult.\n";
		errMsg.append("Expected DOMNode::ELEMENT_NODE");
		throw DOMOvalXMLAnalyzerException(errMsg);
	}


	//	define variables
	int result = UNKNOWN_TEST_RESULT;	//	store the result - default to UNKNOWN_TEST_RESULT
	int tmpResult = -999;				//	tmp holder for results - -999 indicating an error occured. This value should never be reported					//	
	string myDataType;					//	oval node's myDataType
	string myCurChildName;				//	oval node's current child's name
	string myOperator;					//	oval node's operator
	bool dataExistsFlag;				//	data node's exists flag.
	DOMNode *child;						//	
	DOMNodeList *ovalNodeChildList;		//	list of child nodes for the oval node

	/****************************************************************/
	//	The following section gets the exists flag form the data node
	//	and the operator from the oval node. Then if the oval node's
	//	operator is 'exists' or 'does not exist' checks the existance 
	//	flag found on the data node. This should really be done in the 
	//	Compare() function. Actually it is done there too. This code 
	//	should be removed when a better solution is found that handles
	//	windows file paths. This code is only needed to handle a windows
	//	file test's path element. This stops the code from processing 
	//	the path components for a file path that was not found.
	//	BEGIN PATH WORK AROUND
	/****************************************************************/

	//	Get data node's exists flag
	string tmpExists = DOMCommon::GetAttributeByName(dataNode, "exists");
	if(tmpExists.compare("true") == 0)
		dataExistsFlag = true;
	else if(tmpExists.compare("false") == 0)
		dataExistsFlag = false;
	else if(tmpExists.compare("") == 0)
		dataExistsFlag = true;			
	else
	{
		string errMsg = "Error: Invalid value for exists attribute on a element in the oval data document.\n\tFound: ";
		errMsg.append(tmpExists);
		throw DOMOvalXMLAnalyzerException(errMsg);
	}

	//	Get my operator based on the useParentOp flag
	if(useParentOp)
	{
		myOperator = parentOp;			
	}else
	{			
		myOperator = DOMCommon::GetAttributeByName(ovalNode, "operator");
		if(myOperator.compare("") == 0)
			myOperator = "exists";
	}

	//	If the data node's existance flag is false and this is just an existance test return
	if(myOperator.compare("exists") == 0 && !dataExistsFlag)
		return FALSE_TEST_RESULT;
	else if(myOperator.compare("does not exist") == 0 && dataExistsFlag)
		return FALSE_TEST_RESULT;

	/****************************************************************/
	//	END PATH WORK AROUND
	/****************************************************************/

	//	Get my datatype based on the useParentDataType flag
	//	6-16-2004 May not need the use parent datatype flag anymore
	if(useParentDataType)
	{
		myDataType = parentDataType;			
	}else
	{			
		myDataType = DOMCommon::GetAttributeByName(ovalNode, "datatype");
		if(myDataType.compare("") == 0)
			myDataType = "string";
	}

	//	check for child nodes of the ovalNode that are ELEMENT_NODE's
	ovalNodeChildList = ovalNode->getChildNodes();
	unsigned int childCount = ovalNodeChildList->getLength();
	if(childCount > 1 || (childCount == 1 && (ovalNodeChildList->item(0))->getNodeType() == DOMNode::ELEMENT_NODE))
	{
		//	Loop through the child nodes
		unsigned int index = 0;
		while(index < childCount)
		{
			child = ovalNodeChildList->item(index++);

			//	Only process ELEMENT_NODES
			if(child->getNodeType() == DOMNode::ELEMENT_NODE)
			{
				//	Get the child node's name
				myCurChildName = DOMCommon::ToString(child->getNodeName());

				//	Ignore the notes element
				if(myCurChildName.compare("notes") == 0)
					continue;
				
				//	If datatype is version just call CompareVersion() otherwise make recursive call 
				string childDataType = DOMCommon::GetAttributeByName(child, "datatype");
				if(myDataType.compare("") == 0)
					childDataType = "string";
				if(childDataType.compare("version") == 0)
				{
					tmpResult = CompareVersion(child, DOMCommon::FindNode(dataNode, myCurChildName));
								
				}else
				{
					//	If the result is an UNKNOWN_TEST_RESULT or FALSE_TEST_RESULT
					//	break out of the while loop that is processing the node's children
					//	the tmpResult. Otherwise, keep processing the child elements of 
					//	the oval node. This can be done since the elements in a test are
					//	and'ed together by default.

					//	find the corresponding child node in the dataNode and call self
					tmpResult = ComputeSimpleTestResult(child, DOMCommon::FindNode(dataNode, myCurChildName), parentOp, useParentOp, parentDataType, useParentDataType);					
					
				}

				//	Since all child nodes of a test are implictly AND'ed together
				//	stop looping if any result other than a true is found.
				if(tmpResult != TRUE_TEST_RESULT)
					break;
			}
		}

		result = tmpResult;

	//	No children, compute the result
	}else
	{	
		//	Call the compare function to get the result
		result = Compare(ovalNode, dataNode);		
	}

	return result;	
}

void DOMOvalXMLAnalyzer::EvaluateCompoundTest(DOMNode *node)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Recursively evaluate compound tests. Compound tests may consist of other
	//	compound tests. Before a given compound test can be evaluated the sub tests
	//	that make up the compound test must be evaluated. It is assumed that all
	//	simple tests have been evaluated before this function starts. However, any 
	//	compound tests that are part of the provided compound test must be evaluated before
	//	the provided compound test can be evaluated. This will be done recursively as follows:
	//		0- If already processed return
	//		1- Loop through the subtests
	//		2- If a subtest refers to a compound test check if it has been evaluated. If not 
	//			call the EvaluateCompoundTest function.
	//		3- Get the result for each subtest in the compound test
	//		4- Evaluate the compound test.
	// -----------------------------------------------------------------------

	string id				= "";
	string nodeName			= "";
	string test_ref			= "";
	string subTestResult	= "";
	DOMNode *child			= NULL;
	DOMNode *tmp			= NULL;
	
	///////////////////////////////////////////////////////////////////////////
	//	Check if the compound test has already been procesed.
	//	Return if already processed
	///////////////////////////////////////////////////////////////////////////
	if((DOMCommon::GetAttributeByName(node, "result")).compare("") != 0)
		return;


	///////////////////////////////////////////////////////////////////////////
	//	Process the compound test. If an embeded compound test is found
	//	call self otherwise get the result for each subtest and add
	//	a result attribute to the subtest
	///////////////////////////////////////////////////////////////////////////
	
	//	get the test id
	id = DOMCommon::GetAttributeByName(node, "id");

	//	Get the Result for each subtest
	for (child = node->getFirstChild(); child != 0; child=child->getNextSibling())
	{
		// Only consider ELEMENT_NODES
		if(child->getNodeType() == DOMNode::ELEMENT_NODE)
		{
			//	Get the child nodes name
			nodeName = DOMCommon::ToString(child->getNodeName());

			if(nodeName.compare("subtest")==0)
			{
				//	Get the test_ref attribute
				test_ref = DOMCommon::GetAttributeByName(child, "test_ref");

				//	Find the corresponding test node
				tmp = DOMCommon::FindNodeByAttribute(ovalDoc, "id", test_ref);

				if(tmp == NULL)
				{
					if(Log::verboseMode)
					{
						Log::WriteLog("Error: Unable to find a corresponding test for test_ref: " + test_ref = "\n");
						cout << "Error: Unable to find a corresponding test for test_ref: " << test_ref << endl;
					}
					subTestResult = "-1";
				}else
				{
					// If the test_ref is to another compound test call self
					if(strncmp(test_ref.c_str(), "cmp", 3) == 0)
					{
						EvaluateCompoundTest(tmp);				

					//	If test_ref is to an unknown_test call EvaluateUnknownTest
					}else if(strncmp(test_ref.c_str(), "ukn", 3) == 0)
					{
						EvaluateUnknownTest(tmp);

					//	If test_ref is to a simple test call EvaluateSimpleTest
					}else
					{
						EvaluateSimpleTest(tmp);
					}

					//	Get the result attribute
					subTestResult = DOMCommon::GetAttributeByName(tmp, "result");
				}
	
				//	Write result as an attribute to the subtest
				DOMCommon::AddAttribute((DOMElement*)child, "result", subTestResult);
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//	Based on the operation compute the compound test result and 
	//	add the result attribute to the compouind test.
	///////////////////////////////////////////////////////////////////////////
	string result = "";
	
	//	get the value of operation
	string myOp = "";
	myOp = DOMCommon::GetDataNodeValue(DOMCommon::FindNode(node, "operation"));
	
	//	Validate operation
	if(myOp.compare("AND") != 0 && myOp.compare("OR") != 0 && myOp.compare("XOR") != 0 && myOp.compare("") != 0)
	{
		Log::WriteLog("Error: Unsupported operation in compound_test id: " + id + " operation: " + myOp + "\n");
		throw DOMOvalXMLAnalyzerException("Error: Unsupported operation in compound_test id: " + id + " operation: " + myOp + "\n");
	}
	
	string tmpResult = "";
	//	Process subtests based on operation
	for (child = node->getFirstChild(); child != 0; child=child->getNextSibling())
	{
		// Only consider ELEMENT_NODES
		if(child->getNodeType() == DOMNode::ELEMENT_NODE)
		{
			//	Get the child nodes name
			nodeName = DOMCommon::ToString(child->getNodeName());

			if(nodeName.compare("subtest")==0)
			{
				//	Get the result attribute
				subTestResult = DOMCommon::GetAttributeByName(child, "result");
				
				//	Handle the negate attribute
				if((DOMCommon::GetAttributeByName(child, "negate")).compare("true") == 0)
				{
					if(subTestResult.compare("0") == 0)
						subTestResult = "1";
					else if(subTestResult.compare("1") == 0)
						subTestResult = "0";
				}

				if(myOp.compare("AND") == 0)
				{
					if(subTestResult.compare("0") == 0)
					{
						result = "0";
						break;

					}else if(subTestResult.compare("-1") == 0)
					{
						tmpResult = "-1";
					}

				}else if(myOp.compare("OR") == 0)
				{
					if(subTestResult.compare("1") == 0)
					{
						result = "1";
						break;

					}else if(subTestResult.compare("-1") == 0)
					{
						tmpResult = "-1";
					}

				}else if(myOp.compare("XOR") == 0)
				{
					if(subTestResult.compare("-1") == 0)
					{
						result = "-1";
						break;

					//	if a true is found and not already true then true
					}else if(subTestResult.compare("1") == 0 && tmpResult.compare("1") != 0)
					{
						tmpResult = "1";

					//	if a true is found and already true then false
					}else if(subTestResult.compare("1") == 0 && tmpResult.compare("1") == 0)
					{
						tmpResult = "0";
					}
				}	

			}	//	end check if a subtest

		}	//	end check if element node

	}	//	end for loop over subtests

	//	Complete combining of subtest results based on operation
	if(myOp.compare("AND") == 0 && result.compare("") == 0)
	{	
		if(tmpResult.compare("-1") == 0)
			result = "-1";
		else
			result = "1";
	}else if(myOp.compare("OR") == 0 && result.compare("") == 0)
	{
		if(tmpResult.compare("-1") == 0)
			result = "-1";
		else
			result = "0";
	}else if(myOp.compare("XOR") == 0 && result.compare("") == 0)
	{
		if(tmpResult.compare("1") == 0)
			result = "1";
		else
			result = "0";
	}

	//	Add the result attribute to the compound test
	DOMCommon::AddAttribute((DOMElement*)node, "result", result);

	//	Add the compound test to the result document
	myResultXML->AddCompoundTest((DOMElement*)node);
}
 
int DOMOvalXMLAnalyzer::EvaluateDefinition(DOMNode *def)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Remove unwanted elements from the definition element.
	//	Evaluate the criteria. This will result in calls to EvaluateSimpleTest(),
	//	EvaluateCompoundTest(), and EvaluateUnknownTest()	
	// -----------------------------------------------------------------------

	DOMNode *tmpNode		= NULL;
	DOMNode *criteria		= NULL;
	DOMNode *criterion		= NULL;
	DOMNode *software		= NULL;
	DOMNode *configuration	= NULL;
	string configOp			= "";
	string softOp			= "";
	string test_ref			= "";
	string defId			= DOMCommon::GetAttributeByName(def, "id");
	string tmpResult		= "";
	string configResult		= "";
	string sftResult		= "";
	bool foundConfig		= false;
	bool foundSoft			= false;


	///////////////////////////////////////////////////////////////////////////
	//	Process criteria
	///////////////////////////////////////////////////////////////////////////
	
	//	Get the criteria node
	criteria = DOMCommon::FindNode(def, "criteria");
	if(criteria == NULL)
		throw DOMOvalXMLAnalyzerException("Error: Unable to find the \"criteria\" element while evaluating definition " + defId ); 

	
	///////////////////////////////////////////////////////////////////////////
	//	Process the software node
	///////////////////////////////////////////////////////////////////////////

	//	Get the software node
	software = DOMCommon::FindNode(criteria, "software");

	if(software != NULL)
	{
		foundSoft = true;

		//	Get the software node's operation
		softOp = DOMCommon::GetAttributeByName(software, "operation");

		//	For each cirterion determine and set the value of the result attribute
		for (criterion = software->getFirstChild(); criterion != NULL; criterion=criterion->getNextSibling())
		{
			if(criterion->getNodeType() == DOMNode::ELEMENT_NODE)
			{
				if((DOMCommon::ToString(criterion->getNodeName())).compare("criterion") == 0)
				{
					try
					{
						//	Get test_ref attribute and validate it
						test_ref = DOMCommon::GetAttributeByName(criterion, "test_ref");
						if (test_ref.compare("") == 0)
							throw DOMOvalXMLAnalyzerException("Unable to locate the test_ref attribute for the current criterion.");

						//	Get the corresponding test
						tmpNode = DOMCommon::FindNodeByAttribute(DOMCommon::FindNode((ovalDoc)->getDocumentElement(), "tests"), "id", test_ref);
						if(tmpNode == NULL)
							throw DOMOvalXMLAnalyzerException("Unable to locate the test that corresponds to the current criterion.");

						//	Call EvaluateCompoundTest if this is a compound test ref and get result
						if(strncmp(test_ref.c_str(), "cmp", 3) == 0)
							EvaluateCompoundTest(tmpNode);

						//	If an unknown test just set result to unknown
						else if(strncmp(test_ref.c_str(), "ukn", 3) == 0)
							EvaluateUnknownTest(tmpNode);

						// Call EvaluateSimpleTest if this is a simple test and then get the result
						else
							EvaluateSimpleTest(tmpNode);

						//	Get the result attribute
						tmpResult = DOMCommon::GetAttributeByName(tmpNode, "result");
						
					}catch(Exception ex)
					{
						//	Add the result attribute to the test that failed
						tmpResult = "-1";

						//	Display a message if verbose mode
						if(Log::verboseMode)
						{
							string msg = "     Error: An unexpected error occured while evaluating oval definition ";
							msg.append(defId);
							if(test_ref.compare("") != 0)
							{
								msg.append(" test_ref: ");
								msg.append(test_ref);
							}
							msg.append(".\n     Message: " + ex.GetErrorMessage());

							Log::WriteLog(msg);
							cout << msg << endl;

						}
					}

					//	Set result attribute for the criterion					
					DOMCommon::AddAttribute((DOMElement*)criterion, "result", tmpResult);

					//	Handle the negate attribute
					if((DOMCommon::GetAttributeByName(criterion, "negate")).compare("true") == 0)
					{
						if(tmpResult.compare("0") == 0)
							tmpResult = "1";
						else if(tmpResult.compare("1") == 0)
							tmpResult = "0";
					}

					//	Determine the value of the result attribute for the software element
					if(softOp.compare("AND") == 0 && sftResult.compare("0") != 0)
					{
						//	false if a false is found
						if(tmpResult.compare("0") == 0)
						{
							sftResult = "0";

						//	unknown iff an unknown is found
						}else if(tmpResult.compare("-1") == 0)
						{
							sftResult = "-1";

						//	true iff a true is found and an unknown has not been found
						}else if(tmpResult.compare("1") == 0 && (sftResult.compare("1") == 0 || sftResult.compare("") == 0))
						{
							sftResult = "1";
						}

					}else if(softOp.compare("OR") == 0 && sftResult.compare("1") == 0)
					{
						//	true if a true is found
						if(tmpResult.compare("1") == 0)
						{
							sftResult = "1";

						//	unknown iff a unknown is found and a true is not found
						}else if(tmpResult.compare("-1") == 0)
						{
							sftResult = "-1";

						//	false iff a true or unknown are not found
						}else if(tmpResult.compare("0") == 0 && sftResult.compare("-1") == 0)
						{
							sftResult = "0";
						}

					}else if(softOp.compare("XOR") == 0)
					{
						//	true iff a true is found and either not yet set or a false has been found
						if(tmpResult.compare("1") == 0 && (sftResult.compare("0") == 0 || sftResult.compare("") == 0))
						{
							sftResult = "1";

						//	unknown if a unknown is found
						}else if(tmpResult.compare("-1") == 0)
						{
							sftResult = "-1";

						//	false in all other cases
						}else
						{
							sftResult = "0";
						}

					}else if(softOp.compare("") == 0)
					{
						if(sftResult.compare("") == 0)
							sftResult = tmpResult;
						else
						{
							if(Log::verboseMode)
							{
								Log::WriteLog("Error: No operation was specified. Only one software criterion will be evaluated for definiftion id: " + defId + ".\n");
								cout << "Error: No operation was specified. Only one software criterion will be evaluated for definition id: " << defId << "." << endl;
							}
						}
					}
				}
			}
		}

		criterion = NULL;
		
		//	Set the result value for the software node
		DOMCommon::AddAttribute((DOMElement*)software, "result", sftResult);
	}

	///////////////////////////////////////////////////////////////////////////
	//	Process the configuration node
	///////////////////////////////////////////////////////////////////////////
	//	Get the configuration node
	configuration = DOMCommon::FindNode(criteria, "configuration");

	if(configuration != NULL)
	{
		foundConfig = true;

		//	Get the configuration node's operation
		configOp = DOMCommon::GetAttributeByName(configuration, "operation");

		//	Process the criterion
		for (criterion = configuration->getFirstChild(); criterion != NULL; criterion=criterion->getNextSibling())
		{
			if(criterion->getNodeType() == DOMNode::ELEMENT_NODE)
			{
				if((DOMCommon::ToString(criterion->getNodeName())).compare("criterion") == 0)
				{
					try
					{
						//	Get test_ref attribute
						test_ref = DOMCommon::GetAttributeByName(criterion, "test_ref");
						if (test_ref.compare("") == 0)
							throw DOMOvalXMLAnalyzerException("Unable to locate the test_ref attribute for the current criterion.");

						//	Get the corresponding test
						tmpNode = DOMCommon::FindNodeByAttribute(DOMCommon::FindNode((ovalDoc)->getDocumentElement(), "tests"), "id", test_ref);
						if(tmpNode == NULL)
							throw DOMOvalXMLAnalyzerException("Unable to locate the test that corresponds to the current criterion.");

						//	Call EvaluateCompoundTest if this is a compound test ref and get result
						if(strncmp(test_ref.c_str(), "cmp", 3) == 0)
							EvaluateCompoundTest(tmpNode);

						//	If an unknown test just set result to unknown
						else if(strncmp(test_ref.c_str(), "ukn", 3) == 0)
							EvaluateUnknownTest(tmpNode);

						// Call EvaluateSimpleTest if this is a simple test and then get the result
						else
							EvaluateSimpleTest(tmpNode);

						//	Get the result attribute
						tmpResult = DOMCommon::GetAttributeByName(tmpNode, "result");

					}catch(Exception ex)
					{
						//	Add the result attribute to the test that failed
						tmpResult = "-1";

						//	Display a message if verbose mode
						if(Log::verboseMode)
						{
							string msg = "     Error: An unexpected error occured while evaluating oval definition ";
							msg.append(defId);
							if(test_ref.compare("") != 0)
							{
								msg.append(" test_ref: ");
								msg.append(test_ref);
							}
							msg.append(".\n     Message: " + ex.GetErrorMessage());

							Log::WriteLog(msg);
							cout << msg << endl;

						}
					}

					//	Set result attribute for the criterion					
					DOMCommon::AddAttribute((DOMElement*)criterion, "result", tmpResult);

					//	Handle the negate attribute
					if((DOMCommon::GetAttributeByName(criterion, "negate")).compare("true") == 0)
					{
						if(tmpResult.compare("0") == 0)
							tmpResult = "1";
						else if(tmpResult.compare("1") == 0)
							tmpResult = "0";
					}

					//	Determine the value of the result attribute for the configuration element
					if(configOp.compare("AND") == 0)
					{
						//	false if a false is found
						if(tmpResult.compare("0") == 0)
						{
							configResult = "0";

						//	unknown iff an unknown is found and a false is not found
						}else if(tmpResult.compare("-1") == 0 && configResult.compare("0") != 0)
						{
							configResult = "-1";

						//	true iff a true is found a false or unknown have not been found
						}else if(tmpResult.compare("1") == 0 && (configResult.compare("") == 0 || configResult.compare("1") == 0))
						{
							configResult = "1";
						}

					}else if(configOp.compare("OR") == 0)
					{
						//	true if a true is found
						if(tmpResult.compare("1") == 0)
						{
							configResult = "1";

						//	unknown iff a unknown is found and a true is not found
						}else if(tmpResult.compare("-1") == 0 && configResult.compare("1") == 0)
						{
							configResult = "-1";

						//	false iff a true or unknwn are not found
						}else if(tmpResult.compare("0") == 0 && (configResult.compare("1") == 0 || configResult.compare("-1") == 0))
						{
							configResult = "0";
						}

					}else if(configOp.compare("XOR") == 0)
					{
						//	true iff an true is found and either not yet set or a false has been found
						if(tmpResult.compare("1") == 0 && (configResult.compare("0") == 0 || configResult.compare("") == 0))
						{
							configResult = "1";

						//	unknown if a unknown is found
						}else if(tmpResult.compare("-1") == 0)
						{
							configResult = "-1";

						//	false in all other cases
						}else
						{
							configResult = "0";
						}

					}else if(configOp.compare("") == 0)
					{
						if(configResult.compare("") == 0)
							configResult = tmpResult;
						else
						{
							if(Log::verboseMode)
							{
								Log::WriteLog("Error: No operation was specified. Only one software criterion will be evaluated for definiftion id: " + defId + ".\n");
								cout << "Error: No operation was specified. Only one configuration criterion will be evaluated for definition id: " << defId << "." << endl;
							}
						}
					}
				}
			}
		}

		criterion = NULL;
		
		//	Set the result value for the configuration node
		DOMCommon::AddAttribute((DOMElement*)configuration, "result", configResult);
	}

	///////////////////////////////////////////////////////////////////////////
	//	Set the result value for the criteria
	///////////////////////////////////////////////////////////////////////////
	tmpResult = "";
	if(!useConfiguration)
	{
		if(!foundSoft)
			sftResult = "0";
			
		if(sftResult.compare("") == 0)
			sftResult = "-1";

		DOMCommon::AddAttribute((DOMElement*)criteria, "result", sftResult);
		tmpResult = sftResult;

	}else
	{
		if(sftResult.compare("") == 0)
			sftResult = "-1";

		if(configResult.compare("") == 0)
			configResult = "-1";


		if(foundConfig && foundSoft)
		{
			if(configResult.compare("1") == 0 && sftResult.compare("1") == 0)
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "1");
				tmpResult = "1";
			}else if(configResult.compare("0") == 0 || sftResult.compare("0") == 0)
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "0");
				tmpResult = "0";
			}else
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "-1");
				tmpResult = "-1";
			}

		}else if(!foundConfig && foundSoft)
		{
			if(sftResult.compare("1") == 0)
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "1");
				tmpResult = "1";
			}else if(sftResult.compare("0") == 0)
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "0");
				tmpResult = "0";
			}else
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "-1");
				tmpResult = "-1";
			}
		}else if(foundConfig && !foundSoft)
		{
			if(configResult.compare("1") == 0)
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "1");
				tmpResult = "1";
			}else if(configResult.compare("0") == 0)
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "0");
				tmpResult = "0";
			}else
			{
				DOMCommon::AddAttribute((DOMElement*)criteria, "result", "-1");
				tmpResult = "-1";
			}
		}else if(!foundConfig && !foundSoft)
		{
			DOMCommon::AddAttribute((DOMElement*)criteria, "result", "-1");
			tmpResult = "-1";
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//	Add the Definition to the result file
	///////////////////////////////////////////////////////////////////////////
	myResultXML->AddDefinition((DOMElement*)def);


	///////////////////////////////////////////////////////////////////////////
	//	Return the result for the definition
	///////////////////////////////////////////////////////////////////////////
	if(tmpResult.compare("1") == 0)
		return 1;
	else if(tmpResult.compare("0") == 0)
		return 0;
	else
		return -1;
}

void DOMOvalXMLAnalyzer::EvaluateDefinitions()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Loop through all definitions in the oval document.
	//	Call EvaluateDefinition for each definition in the family being analyzed
	//	Call the print routine to print the results.
	//
	// -----------------------------------------------------------------------

	DOMNode *definitions;
	DOMNode *def;
	DOMNodeList *defList;
	string defFamily;
	string strDefinition;
	int result;
	sVector notVuln;
	sVector vuln;
	sVector unknown;

	//	get a ptr to the definitions node in the oval document.
	definitions = DOMCommon::FindNode(ovalDoc, "definitions");

	//	get a list of the child nodes
	defList = definitions->getChildNodes();

	//	Loop through all the nodes in defList
	unsigned int index = 0;
	while(index < defList->getLength())
	{
		def = defList->item(index++);

		if(def != NULL)
		{
			//	only concerned with ELEMENT_NODEs
			if (def->getNodeType() == DOMNode::ELEMENT_NODE)
			{
				//	Get the name of the node
				string name = DOMCommon::ToString(def->getNodeName());
				
				//	Call the appropriate evaluation function for the current test
				if(name.compare("definition") == 0)
				{
					//	Get the family of the definition
					defFamily = GetDefinitionFamily(def);

					if(defFamily.compare(osFamily) == 0)
					{
						//	Gather information from the definition
						strDefinition = ToString((DOMElement*)def);

						//	Evaluate the definition
						result = EvaluateDefinition(def);

						if(result == 0)
							notVuln.push_back(strDefinition);
						else if(result == 1)
							vuln.push_back(strDefinition);
						else
							unknown.push_back(strDefinition);
					}
				}	
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////
	//	Call the print routine
	///////////////////////////////////////////////////////////////////////////
	Print(&vuln, &notVuln, &unknown);
}
 
void DOMOvalXMLAnalyzer::EvaluateSimpleTest(DOMNode *ovalNode)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Evaluate the simple test by calling ComputeSimpleTestResult. Take the 
	//	return value and set the result attribute for the test. Finally remove
	//	the children of the simple test.
	// -----------------------------------------------------------------------

	///////////////////////////////////////////////////////////////////////////
	//	Check for valid inputs
	//	Throw an exception if invalid input
	///////////////////////////////////////////////////////////////////////////
	if(ovalNode == NULL)
	{
		throw DOMOvalXMLAnalyzerException("Error: Invalid input for EvaluateSimpleTest(). NULL oval node specified.");
	}

	///////////////////////////////////////////////////////////////////////////
	//	Check if the test has already been procesed.
	//	Return if already processed
	///////////////////////////////////////////////////////////////////////////
	if((DOMCommon::GetAttributeByName(ovalNode, "result")).compare("") != 0)
		return;
	
	///////////////////////////////////////////////////////////////////////////
	//	Compute the result
	//	
	//	Loop through all corresponding data nodes Stop looping if a true is found
	//	if an unknown is found continue looping, but store the unknown
	//
	//	This logic assumes that we are checking only one of the data nodes. Meaning 
	//	that if ANY test result is true then the test is true. We may need to add
	//	logic to handle cases in which the test is true only if all test results 
	//	are true
	///////////////////////////////////////////////////////////////////////////

	int tmpResult			= UNKNOWN_TEST_RESULT;
	int result				= UNKNOWN_TEST_RESULT;
	NodeVector *dataNodes	= NULL;

	dataNodes = GetMatchingDataNodes(ovalNode);
	NodeVector::iterator nodeIterator;
	for (nodeIterator=dataNodes->begin(); nodeIterator!=dataNodes->end(); nodeIterator++)
	{
		tmpResult = ComputeSimpleTestResult(ovalNode, (*nodeIterator));
		if(tmpResult == TRUE_TEST_RESULT)
		{
			result = tmpResult;
			break;
		}else if(tmpResult == UNKNOWN_TEST_RESULT && result != FALSE_TEST_RESULT)
		{
			result = tmpResult;
		}else if(tmpResult == FALSE_TEST_RESULT)
		{
			result = tmpResult;
		}		
	}

	///////////////////////////////////////////////////////////////////////////
	//	Add the result attribute to the ovalNode
	///////////////////////////////////////////////////////////////////////////
	DOMCommon::AddAttribute((DOMElement*)ovalNode, "result", Common::ToString(result));

	///////////////////////////////////////////////////////////////////////////
	//	Add the test to the result document
	///////////////////////////////////////////////////////////////////////////
	myResultXML->AddTest((DOMElement*)ovalNode);
}

void DOMOvalXMLAnalyzer::EvaluateUnknownTest(DOMNode *uknTest)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Just add the result attribute to the test and set it to '-1'
	// -----------------------------------------------------------------------

	///////////////////////////////////////////////////////////////////////////
	//	Check if the test has already been procesed.
	//	Return if already processed
	///////////////////////////////////////////////////////////////////////////
	if((DOMCommon::GetAttributeByName(uknTest, "result")).compare("") != 0)
		return;

	//	Check that the test is an unknown_test
	string name = DOMCommon::ToString(uknTest->getNodeName());
	if(strncmp(name.c_str(), "unknown_test", 12)!=0)
		throw DOMOvalXMLAnalyzerException("Error: EvaluateUnknownTest() expected an unknown_test. Found: " + name);

	DOMCommon::AddAttribute((DOMElement*)uknTest, "result", "-1");

	///////////////////////////////////////////////////////////////////////////
	//	Add the test to the result document
	///////////////////////////////////////////////////////////////////////////
	myResultXML->AddTest((DOMElement*)uknTest);
}

string DOMOvalXMLAnalyzer::GetDefinitionFamily(DOMNode *def)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the family that the provided definition node corresponds to
	// -----------------------------------------------------------------------

	//	Get the node name
	string name = DOMCommon::ToString(def->getNodeName());
	string strFamily = "";
	DOMNode *tmpNode = NULL;

	if(name.compare("definition") == 0)
	{
		//	Get the affected family
		tmpNode = DOMCommon::FindNode(def, "affected");
		if(tmpNode != NULL)
			strFamily = DOMCommon::GetAttributeByName(tmpNode, "family");
	}else
	{
		throw DOMOvalXMLAnalyzerException("Error: GetDefinitionFamily() can not process a \"" + name + "\" node.");	
	}

	return strFamily;
}

NodeVector* DOMOvalXMLAnalyzer::GetMatchingDataNodes(DOMNode *ovalNode)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a ptr to the data node the corresponds to the oval test node 
	//	provided. Return NULL if not found.
	//
	// -----------------------------------------------------------------------

	NodeVector *results = NULL;
	string name;

	//	get the name of the provided node
	name = XMLString::transcode(ovalNode->getNodeName());

	//	Now call the search function on the data file
	results = DOMCommon::FindAllNodes(dataDoc, name, "id", DOMCommon::GetAttributeByName(ovalNode, "id"));
	
	return (results);
}

void DOMOvalXMLAnalyzer::Print(sVector *vuln, sVector *notVuln, sVector *unknown)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Print the results of the analysis
	//
	// -----------------------------------------------------------------------

	///////////////////////////////////////////////////////////////////////////
	//	Display a header indicating that the definitions are being processed
	///////////////////////////////////////////////////////////////////////////
	cout << " ** OVAL definition results.\n" << endl;
	Log::WriteLog(" ** OVAL definition results.\n\n");

	///////////////////////////////////////////////////////////////////////////
	//	Print the vulnerable results
	///////////////////////////////////////////////////////////////////////////
	if(vuln->size() == 0)
	{
		cout << "    VULNERABILITIES FOUND:" << endl;
		cout << "    OVAL Id" << "\tCVE Id" << endl;
		cout << "    -------------------------" << endl;
		cout << "    None." << endl;
		cout << "    -------------------------\n" << endl;
		Log::WriteLog("    VULNERABILITIES FOUND:\n");
		Log::WriteLog("    OVAL Id\tCVE Id\n");
		Log::WriteLog("    -------------------------\n");
		Log::WriteLog("    None\n");
		Log::WriteLog("    -------------------------\n\n");
	
	}else
	{
		cout << "    VULNERABILITIES FOUND:" << endl;
		cout << "    OVAL Id" << "\tCVE Id" << endl;
		cout << "    -------------------------" << endl;
		Log::WriteLog("    VULNERABILITIES FOUND:\n");
		Log::WriteLog("    OVAL Id\tCVE Id\n");
		Log::WriteLog("    -------------------------\n");
		sVector::iterator vulnIterator;
		for (vulnIterator=vuln->begin(); vulnIterator!=vuln->end(); vulnIterator++)
		{
			cout << (*vulnIterator) << endl;
			Log::WriteLog((*vulnIterator) + "\n");
		}

		cout << "    -------------------------\n" << endl;
		Log::WriteLog("    -------------------------\n\n");
	}

	///////////////////////////////////////////////////////////////////////////
	//	Print the not vulnerable results
	///////////////////////////////////////////////////////////////////////////
	if(notVuln->size() == 0)
	{
		cout << "    VULNERABILITIES NOT FOUND:" << endl;
		cout << "    OVAL Id" << "\tCVE Id" << endl;
		cout << "    -------------------------" << endl;
		cout << "    None." << endl;
		cout << "    -------------------------\n" << endl;
		Log::WriteLog("    VULNERABILITIES NOT FOUND:\n");
		Log::WriteLog("    OVAL Id\tCVE Id\n");
		Log::WriteLog("    -------------------------\n");
		Log::WriteLog("    None\n");
		Log::WriteLog("    -------------------------\n\n");
	
	}else
	{
		cout << "    VULNERABILITIES NOT FOUND:" << endl;
		cout << "    OVAL Id" << "\tCVE Id" << endl;
		cout << "    -------------------------" << endl;
		Log::WriteLog("    VULNERABILITIES NOT FOUND:\n");
		Log::WriteLog("    OVAL Id\tCVE Id\n");
		Log::WriteLog("    -------------------------\n");
		sVector::iterator notvulnIterator;
		for (notvulnIterator=notVuln->begin(); notvulnIterator!=notVuln->end(); notvulnIterator++)
		{
			cout << (*notvulnIterator) << endl;
			Log::WriteLog((*notvulnIterator) + "\n");
		}
	
		cout << "    -------------------------\n" << endl;
		Log::WriteLog("    -------------------------\n\n");
	}
	

	///////////////////////////////////////////////////////////////////////////
	//	Print the unknown results
	///////////////////////////////////////////////////////////////////////////
	if(unknown->size() == 0)
	{
		cout << "    UNABLE TO DETERMINE RESULT:" << endl;
		cout << "    OVAL Id" << "\tCVE Id" << endl;
		cout << "    -------------------------" << endl;
		cout << "    None." << endl;
		cout << "    -------------------------\n" << endl;
		Log::WriteLog("    UNABLE TO DETERMINE RESULT:\n");
		Log::WriteLog("    OVAL Id\tCVE Id\n");
		Log::WriteLog("    -------------------------\n");
		Log::WriteLog("    None\n");
		Log::WriteLog("    -------------------------\n\n");
	
	}else
	{
		cout << "    UNABLE TO DETERMINE RESULT:" << endl;
		cout << "    OVAL Id" << "\tCVE Id" << endl;
		cout << "    -------------------------" << endl;
		Log::WriteLog("    UNABLE TO DETERMINE RESULT:\n");
		Log::WriteLog("    OVAL Id\tCVE Id\n");
		Log::WriteLog("    -------------------------\n");

		sVector::iterator unknownIterator;
		for (unknownIterator=unknown->begin(); unknownIterator!=unknown->end(); unknownIterator++)
		{
			cout << (*unknownIterator) << endl;
			Log::WriteLog((*unknownIterator) + "\n");
		}

		cout << "    -------------------------\n" << endl;
		Log::WriteLog("    -------------------------\n\n");
	}

	///////////////////////////////////////////////////////////////////////////
	//	Display a footer  indicating that the definitions have completed
	///////////////////////////////////////////////////////////////////////////
	cout << "\n ** finished evaluating OVAL  definitions.\n" << endl;	
	Log::WriteLog("\n ** finished evaluating OVAL  definitions.\n\n");
}


void DOMOvalXMLAnalyzer::SetOSFamily()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the osFamily for this DOMOvalXMLAnalyzer
	//
	// -----------------------------------------------------------------------
	
	string attVal;
		
	DOMNode *oval_data_Node = DOMCommon::FindNode(dataDoc, "system_characteristics");

	if(oval_data_Node != NULL)
	{
		//	get the family attribute
		attVal = DOMCommon::GetAttributeByName(oval_data_Node, "family");
		if(attVal.compare("") != 0)
		{
			osFamily = attVal;
		}else
		{
			//	set osFamily to error
			osFamily = "error";
			throw DOMOvalXMLAnalyzerException("Could not find the family attribute for the system_characteristics node in the data document.");
		}

	}else
	{
		//	set osFamily to error
		osFamily = "error";
		throw DOMOvalXMLAnalyzerException("Could not find the system_characteristics node in the data document.");
	}

	///////////////////////////////////////////////////////////////////////////
	//	Display a nice message indicating what family is being processed
	///////////////////////////////////////////////////////////////////////////
	cout << " ** set to process " << osFamily << " OVAL definitions." << endl;	
	Log::WriteLog(" ** set to process " + osFamily + " OVAL definitions.\n");
	

}

string DOMOvalXMLAnalyzer::ToString(DOMElement *definition)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a string representation of a definition.
	//
	// -----------------------------------------------------------------------

	string strDefinition = "";

	//	Ensure that the element provided is a definition
	string name = DOMCommon::ToString(definition->getNodeName());
	if(name.compare("definition") != 0)
		throw DOMOvalXMLAnalyzerException("Error: Called ToString() with a node other than a definition node. Node name: " + name + ".");

	//	Get the CVE id
	DOMNode *cve = DOMCommon::FindNode(definition, "cveid");
	string strCVE = "";
	if(cve == NULL)
		strCVE = "Not specified";
	else
		strCVE = DOMCommon::GetAttributeByName(cve, "status") + "-" + DOMCommon::GetDataNodeValue(cve);
	

	strDefinition.append("    " + DOMCommon::GetAttributeByName(definition, "id") + "\t" + strCVE);


	return strDefinition;
}

//****************************************************************************************//
//							DOMOvalXMLAnalyzerException Class							  //	
//****************************************************************************************//
DOMOvalXMLAnalyzerException::DOMOvalXMLAnalyzerException() : Exception()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Default constructor simply set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class default constructor.
	//
	// -----------------------------------------------------------------------

}

DOMOvalXMLAnalyzerException::DOMOvalXMLAnalyzerException(string errMsgIn) : Exception(errMsgIn)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the error message and then set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class constructor that 
	//	takes a single string param.
	//
	// -----------------------------------------------------------------------

}

DOMOvalXMLAnalyzerException::~DOMOvalXMLAnalyzerException()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothingfor now
	//
	// -----------------------------------------------------------------------

}

