//
// $Id: OvalResultXml.cpp,v 1.21 2005/08/10 16:17:30 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2005, The MITRE Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice, this list
//       of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//       list of conditions and the following disclaimer in the documentation and/or other
//       materials provided with the distribution.
//     * Neither the name of The MITRE Corporation nor the names of its contributors may be
//       used to endorse or promote products derived from this software without specific 
//       prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//****************************************************************************************//


#include "OvalResultXml.h"

const string OvalResultXml::OVALRESULTSNS = "http://oval.mitre.org/XMLSchema/oval_results";
const string OvalResultXml::OVALRESULTSALIAS = "oval_results";
const string OvalResultXml::OVALRESULTSCHEMALOCATION = "oval-results-schema.xsd";
const string OvalResultXml::WINDOWSALIAS = "windows";
const string OvalResultXml::WINDOWSSCHEMALOCATION = "windows-oval-results-schema.xsd";
const string OvalResultXml::DEBIANALIAS = "debian";
const string OvalResultXml::DEBIANSCHEMALOCATION = "debian-oval-results-schema.xsd";
const string OvalResultXml::INDEPENDENTALIAS = "independent";
const string OvalResultXml::INDEPENDENTSCHEMALOCATION = "independent-oval-results-schema.xsd";
const string OvalResultXml::IOSALIAS = "ios";
const string OvalResultXml::IOSSCHEMALOCATION = "ios-oval-results-schema.xsd";
const string OvalResultXml::MACOSALIAS = "macos";
const string OvalResultXml::MACOSSCHEMALOCATION = "macos-oval-results-schema.xsd";
const string OvalResultXml::REDHATALIAS = "redhat";
const string OvalResultXml::REDHATSCHEMALOCATION = "redhat-oval-results-schema.xsd";
const string OvalResultXml::SOLARISALIAS = "solaris";
const string OvalResultXml::SOLARISSCHEMALOCATION = "solaris-oval-results-schema.xsd";
const string OvalResultXml::UNIXALIAS = "unix";
const string OvalResultXml::UNIXSCHEMALOCATION = "unix-oval-results-schema.xsd";
const string OvalResultXml::XMLSIGNS = "http://www.w3.org/2000/09/xmldsig#";
const string OvalResultXml::XMLSIGALIAS = "ds";
const string OvalResultXml::XMLSIGSCHEMALOCATION = "xmldsig-core-schema.xsd";

//****************************************************************************************//
//								OvalResultXml Class										  //
//****************************************************************************************//

OvalResultXml::OvalResultXml(XmlProcessor *myProcessor, string familyIn, 
								XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *ovalDoc, 
								XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *dataDoc)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a new OvalResultXml
	//	Initialize all member data. Create the result document..
	// -----------------------------------------------------------------------
	
	// Validate the oval and the data document
	if(ovalDoc == NULL)
		throw OvalResultXmlException("Error: A NULL oval document has been specified for analysis.");
	if(dataDoc == NULL)
		throw OvalResultXmlException("Error: A NULL data document has been specified for analysis.");

	//	Set the family
	family = familyIn;

	//	Create the result document
	resultDocument = myProcessor->CreateDOMDocumentNS("http://oval.mitre.org/XMLSchema/oval_results","oval_results");


	//	Get a reference to the oval_result node
	DOMNode *oval_resultNode = XmlCommon::FindNode(resultDocument, "oval_results");
	if(oval_resultNode == NULL)
		throw OvalResultXmlException("Error: Unable to locate the oval_results node in the result document.");

	//	Set namespace info for result document
	XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
	XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xmlns:oval_results", "http://oval.mitre.org/XMLSchema/oval_results");
	XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xsi:schemaLocation", "http://oval.mitre.org/XMLSchema/oval_results oval-results-schema.xsd");


	/* 
	In version 4.1 of OVAL i can no longer assume that the only namespace that needs to be added is the family specific
	namespace. namepaces no longer havea 1 to 1 mapping to families. This requires namespaces to be added as they are 
	encountered. Namespaces can be encountered while adding an unknown test, a coumpound test, a simple test, or a 
	definition. Each of the functions that handles these items will be adjusted to update the namespace info on the 
	results document that is being generated.


	if(family.compare("windows") == 0) {

		familyXMLNS = "http://oval.mitre.org/XMLSchema/oval_results#windows";
		familyXMLNSQualifier = "windows:";
		xsiSchemaLocation = "http://oval.mitre.org/XMLSchema/oval_results oval-results-schema.xsd http://oval.mitre.org/XMLSchema/oval_results#windows windows-oval-results-schema.xsd";
		XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xmlns:windows", familyXMLNS.c_str());
		XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xsi:schemaLocation", xsiSchemaLocation.c_str());

	} else if(family.compare("redhat") == 0) {

		familyXMLNS = "http://oval.mitre.org/XMLSchema/oval_results#redhat";
		familyXMLNSQualifier = "redhat:";
		xsiSchemaLocation = "http://oval.mitre.org/XMLSchema/oval_results oval-results-schema.xsd http://oval.mitre.org/XMLSchema/oval_results#redhat redhat-oval-results-schema.xsd";
		XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xmlns:redhat", familyXMLNS.c_str());
		XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xsi:schemaLocation", xsiSchemaLocation.c_str());

	} else if(family.compare("solaris") == 0) {

		familyXMLNS = "http://oval.mitre.org/XMLSchema/oval_results#solaris";
		familyXMLNSQualifier = "solaris:";
		xsiSchemaLocation = "http://oval.mitre.org/XMLSchema/oval_results oval-results-schema.xsd http://oval.mitre.org/XMLSchema/oval_results#solaris solaris-oval-results-schema.xsd";
		XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xmlns:redhat", familyXMLNS.c_str());
		XmlCommon::AddAttribute((DOMElement*)oval_resultNode, "xsi:schemaLocation", xsiSchemaLocation.c_str());
	
	// Need to add other families here as we support them IOS?
	} else {

		familyXMLNS = "";
		familyXMLNSQualifier = "";
		xsiSchemaLocation = "";
	}

	*/


	// Add the generators element
	AddGenerators(ovalDoc, dataDoc);

	// Add the system_info element
	AddSystemInfo(dataDoc);

	//	Add the definitions and tests element to the result document
	DOMElement *definitions = resultDocument->createElement(XMLString::transcode("definitions"));
	DOMElement *tests = resultDocument->createElement(XMLString::transcode("tests"));
	oval_resultNode->appendChild(definitions);
	oval_resultNode->appendChild(tests);
}

OvalResultXml::~OvalResultXml()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	// -----------------------------------------------------------------------
}

// ***************************************************************************************	//
//								Public members												//
// ***************************************************************************************	//
DOMElement* OvalResultXml::AddCompoundTest(string testId, string comment, string operation)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Use the id comment an operation to create a new compound test in the
	//	result document. Return a pointer to the newly created test.
	// -----------------------------------------------------------------------
	
	//	Get a reference to the test element in the result document
	DOMNode *tests = XmlCommon::FindNode(resultDocument, "tests");

	//	Create a new compound test element and add it as a child of tests
	DOMElement *test = resultDocument->createElementNS(XMLString::transcode(this->GetXmlNSForAlias("independent").c_str()), XMLString::transcode("compound_test"));
	tests->appendChild(test);

	//	Set the attributes on the on test element
	XmlCommon::AddAttribute(test, "id", testId);
	XmlCommon::AddAttribute(test, "comment", comment);
	XmlCommon::AddAttribute(test, "operation", operation);
	XmlCommon::AddAttribute(test, "result", "-1");

	// Add the independant namespace to the results document
	this->UpdateNamespaceInfo("independent");

	// Add the version to the test
	// NOTE: this is hard coded for this reference implementation
	// This implementation does not support analyzing tests with 
	// variables with different values. Version is only needed
	// if a test used variables and the varialbes are different
	// for each use of the test in a set of definitions
	XmlCommon::AddAttribute(test, "version", "1");

	return test;
}

void OvalResultXml::AddCriterion(DOMElement *resultDefinition, string type, string negateAttr, string test_refAttr, string criterionResult, string comment)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a new criterion element for the specified definition
	//	using the provided information
	//
	// -----------------------------------------------------------------------

	// Get the parent of the new criterion
	DOMNode *criterionParent = NULL;
	if(type.compare("software") == 0) {
		criterionParent = XmlCommon::FindNode(resultDefinition, "software");
	} else if(type.compare("configuration") == 0) {
		criterionParent = XmlCommon::FindNode(resultDefinition, "configuration");
	} else {
		throw OvalResultXmlException("Error: An invalide criterion type was specified: " + type + ".");
	}

	//	Create a new criterion element and add it to criterionParent
	DOMElement *newCriterion = resultDocument->createElement(XMLString::transcode("criterion"));
	criterionParent->appendChild(newCriterion);

	// Add the criterion attributes
	XmlCommon::AddAttribute(newCriterion, "result", criterionResult);			
	XmlCommon::AddAttribute(newCriterion, "test_ref", test_refAttr);
	XmlCommon::AddAttribute(newCriterion, "negate", negateAttr);
	XmlCommon::AddAttribute(newCriterion, "comment", comment);
	
	// Add the version to the criterion
	// NOTE: this is hard coded for this reference implementation
	// This implementation does not support analyzing tests with 
	// variables with different values. Version is only needed
	// if a test used variables and the varialbes are different
	// for each use of the test in a set of definitions
	XmlCommon::AddAttribute(newCriterion, "version", "1");
}

DOMElement* OvalResultXml::AddDefinition(DOMElement *ovalDefinition)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Read the definition in the oval file and create a new definition
	//	according to the result schema. 
	// -----------------------------------------------------------------------

	//	Get the definition id from the oval definition
	string definitionId = XmlCommon::GetAttributeByName(ovalDefinition, "id");

	//	Get the definition class from the oval definition
	string definitionClass = XmlCommon::GetAttributeByName(ovalDefinition, "class");

	//	Get a reference to the definitions element in the result document
	DOMNode *definitions = XmlCommon::FindNode(resultDocument, "definitions");

	//	Create a new definition element and add it as a child of definitions
	DOMElement *definition = resultDocument->createElement(XMLString::transcode("definition"));
	definitions->appendChild(definition);

	//	Add the id to the definition element
	XmlCommon::AddAttribute(definition, "id", definitionId);

	//	Add the class to the definition element
	XmlCommon::AddAttribute(definition, "class", definitionClass);

	// Add the instance to the definition
	// NOTE: this is hard coded for this reference implementation
	// This implementation does not support analyzing the same definition
	// multiple times with different variables in tests
	XmlCommon::AddAttribute(definition, "instance", "1");


	///////////////////////////////////////////////////////
	//	Copy the affected element 
	///////////////////////////////////////////////////////
	//	Only try to copy if the element exists in the oval definition
	DOMElement *ovalAffected = XmlCommon::FindNodeNS(ovalDefinition, "affected");
	
	if (ovalAffected != NULL) {

		//	Get the family attribute from the affected element in the oval document
		string ovalAffectedFamily = XmlCommon::GetAttributeByName(ovalAffected, "family");

		//	Create a new affected element and add it as a child of the new definition
		DOMElement *affected = resultDocument->createElement(XMLString::transcode("affected"));
		definition->appendChild(affected);

		//	Add the family attribute to the new affected element
		XmlCommon::AddAttribute(affected, "family", ovalAffectedFamily);

		//	Copy all the platform elements and all the product elements
		for (DOMNode *tmpNode = ovalAffected->getFirstChild(); tmpNode != NULL; tmpNode=tmpNode->getNextSibling()) {
			//	only look at DOMElement nodes
			if(tmpNode->getNodeType() == DOMNode::ELEMENT_NODE) {
				DOMElement* ovalProductOrPlatform = (DOMElement*)tmpNode;
				// Get the element name
				string ovalElementName = XmlCommon::GetElementName((DOMElement*)ovalProductOrPlatform);

				// Is it a platform element
				if(ovalElementName.compare("platform") == 0) {

                    // get the namespace prefix
					string ovalElementPrefix = XmlCommon::GetElementPrefix((DOMElement*)ovalProductOrPlatform);

					//	Get the value of the oval platform
					string ovalPlatform = XmlCommon::GetDataNodeValue(ovalProductOrPlatform);

					//	Create a new node and set its value
					CreateNodeWithValue(affected, ovalElementPrefix+":platform", ovalPlatform);

					// update the namespaces
					this->UpdateNamespaceInfo(ovalElementPrefix);

				// Is it a product element
				}else if(ovalElementName.compare("product") == 0) {
					//	Get the value of the oval product
					string ovalProduct = XmlCommon::GetDataNodeValue(ovalProductOrPlatform);

					//	Create a new node and set its value
					CreateNodeWithValue(affected, "product", ovalProduct);
				}
			}
		}
	}

	///////////////////////////////////////////////////////
	//	Copy the description element
	///////////////////////////////////////////////////////
	//	Get a reference to the description in the oval definition
	DOMElement *ovalDescription = XmlCommon::FindNodeNS(ovalDefinition, "description");

	//	Get the value of the description from the oval definition
	string ovalDescriptionValue = XmlCommon::GetDataNodeValue(ovalDescription);

	//	Create a new description element and add it as a child of definition and set its value
	CreateNodeWithValue(definition, "description", ovalDescriptionValue);

	///////////////////////////////////////////////////////
	//	Copy the reference element
	///////////////////////////////////////////////////////
	//	Only try to copy if the element exists in the oval definition
	DOMElement *ovalReference = XmlCommon::FindNodeNS(ovalDefinition, "reference");
	
	if (ovalReference != NULL) {
		//	Get the status attribute and the value of the cve element
		//	from the oval definition
		string ovalReferenceSource = XmlCommon::GetAttributeByName(ovalReference, "source");
		string ovalReferenceValue = XmlCommon::GetDataNodeValue(ovalReference);

		//	Create a new reference element and add it as a child of definition and set its value
		DOMElement *reference = CreateNodeWithValue(definition, "reference", ovalReferenceValue);

		//	Add the status attribute to the new cve element
		XmlCommon::AddAttribute(reference, "source", ovalReferenceSource);
	}

	///////////////////////////////////////////////////////
	//	Copy the status element
	///////////////////////////////////////////////////////
	//	Get a reference to the status in the oval definition
	DOMElement *ovalStatus = XmlCommon::FindNodeNS(ovalDefinition, "status");

	//	Get the value of the status from the oval definition
	string ovalStatusValue = XmlCommon::GetDataNodeValue(ovalStatus);

	//	Create a new status element and add it as a child of definition and set its value
	CreateNodeWithValue(definition, "status", ovalStatusValue);

	///////////////////////////////////////////////////////
	//	Copy the version element
	///////////////////////////////////////////////////////
	//	Get a reference to the version in the oval definition
	DOMElement *ovalVersion = XmlCommon::FindNodeNS(ovalDefinition, "version");

	//	Get the value of the version from the oval definition
	string ovalVersionValue = XmlCommon::GetDataNodeValue(ovalVersion);

	//	Create a new version element and add it as a child of definition and set its value
	CreateNodeWithValue(definition, "version", ovalVersionValue);

	///////////////////////////////////////////////////////
	//	Copy the criteria element
	///////////////////////////////////////////////////////
	//	Create a new criteria element and add it as a child of definition
	DOMElement *criteria = resultDocument->createElement(XMLString::transcode("criteria"));
	definition->appendChild(criteria);

	//	If the oval definition has a software element copy it to the
	//	result document's criteria
	DOMElement *ovalSoftware = XmlCommon::FindNodeNS(ovalDefinition, "software");

	if(ovalSoftware != NULL) {
		//	Get the value of the operation attribute from the oval software node
		string ovalSoftwareOperation = XmlCommon::GetAttributeByName(ovalSoftware, "operation");

		//	Create a new software element and add it as a child of criteria
		DOMElement *software = resultDocument->createElement(XMLString::transcode("software"));
		criteria->appendChild(software);

		//	Add the operation to software
		if(ovalSoftwareOperation.compare("") != 0)
			XmlCommon::AddAttribute(software, "operation", ovalSoftwareOperation);

		// Add a default result attribute
		XmlCommon::AddAttribute(software, "result", "-1");
	}

	//	If the oval definition has a configuration element copy it to the
	//	result document's criteria
	DOMElement *ovalCofiguration = XmlCommon::FindNodeNS(ovalDefinition, "configuration");

	if(ovalCofiguration != NULL)
	{
		//	Get the value of the operation attribute from the oval configuration node
		string ovalConfigurationOperation = XmlCommon::GetAttributeByName(ovalCofiguration, "operation");

		//	Create a new configuration element and add it as a child of criteria
		DOMElement *configuration = resultDocument->createElement(XMLString::transcode("configuration"));
		criteria->appendChild(configuration);

		//	Add the operation attribute to configuration
		if(ovalConfigurationOperation.compare("") != 0)
			XmlCommon::AddAttribute(configuration, "operation", ovalConfigurationOperation);

		// Add a default result attribute
		XmlCommon::AddAttribute(configuration, "result", "-1");
	}

	return definition;
}

void OvalResultXml::AddSubtest(DOMElement *compoundTest, string negateAttr, string test_refAttr, string result)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a new subtest element and add it as a child of newCompoundTest.
	//	Copy id, comment, negate, and result from ovalSubtest
	// -----------------------------------------------------------------------

	//	Create a new subtest element and add it as a child of newCompoundTest
	DOMElement *newSubtest = resultDocument->createElement(XMLString::transcode("subtest"));
	compoundTest->appendChild(newSubtest);

	//	Set attributes on the new subtest
	XmlCommon::AddAttribute(newSubtest, "test_ref", test_refAttr);

	if(negateAttr.compare("true") == 0)
		XmlCommon::AddAttribute(newSubtest, "negate", negateAttr);
	
	XmlCommon::AddAttribute(newSubtest, "result", result);

		// Add the version to the test
	// NOTE: this is hard coded for this reference implementation
	// This implementation does not support analyzing tests with 
	// variables with different values. Version is only needed
	// if a test used variables and the varialbes are different
	// for each use of the test in a set of definitions
	XmlCommon::AddAttribute(newSubtest, "version", "1");
}

DOMElement* OvalResultXml::AddTest(DOMElement *ovalTest)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Read the oval test and add a test to the result document.
	//	Copy the id, comment, and result. Add the correct namespace attribute 
	//	Force tests to be earlier siblings to compound tests.
	// -----------------------------------------------------------------------

	//	Gather the data from the oval test
	string testName = XmlCommon::GetElementName(ovalTest);
	string comment = XmlCommon::GetAttributeByName(ovalTest, "comment");
	string checkAttr = XmlCommon::GetAttributeByName(ovalTest, "check");
	string testId = XmlCommon::GetAttributeByName(ovalTest, "id");
	string xmlns = XmlCommon::ToString(ovalTest->getNamespaceURI());

	// get the alias associated with the namespace
	unsigned int poundSign = xmlns.find('#');
	string xmlnsAlias = "";
	if(poundSign == string::npos) {
		//error
		cout << "error" << endl;
	} else {
		xmlnsAlias = xmlns.substr(poundSign+1, xmlns.length()-poundSign);
	}
	
	//	Get a reference to the test element in the result document
	DOMNode *tests = XmlCommon::FindNode(resultDocument, "tests");

	//	Create a new test element and add it as a child of tests
	DOMElement *test = resultDocument->createElementNS(XMLString::transcode(this->GetXmlNSForAlias(xmlnsAlias).c_str()), XMLString::transcode(testName.c_str()));
	tests->appendChild(test);

	//	Set the attributes on the on test element
	XmlCommon::AddAttribute(test, "id", testId);
	XmlCommon::AddAttribute(test, "check", checkAttr);
	XmlCommon::AddAttribute(test, "comment", comment);
	XmlCommon::AddAttribute(test, "result", "-1");
	
	// Add the namespace that the current test is in to the results document
	this->UpdateNamespaceInfo(xmlnsAlias);

	// Add the version to the test
	// NOTE: this is hard coded for this reference implementation
	// This implementation does not support analyzing tests with 
	// variables with different values. Version is only needed
	// if a test used variables and the varialbes are different
	// for each use of the test in a set of definitions
	XmlCommon::AddAttribute(test, "version", "1");


	// Check for an object section in the ovalTest
	// Add it to the results file if it exists
	DOMNode *defiitionObject = XmlCommon::FindNodeNS(ovalTest, "object");
	if(defiitionObject != NULL)
		AddDefinitionObject(test, (DOMElement*)defiitionObject);


	// Check for a data section in the ovalTest
	// Add it to the results file if it exists
	DOMNode *defiitionData = XmlCommon::FindNodeNS(ovalTest, "data");
	if(defiitionData != NULL)
		AddDefinitionData(test, (DOMElement*)defiitionData);
	
	return test;
}

void OvalResultXml::AddTestMsg(DOMElement *resultTest, string msg)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add the provided message to the result test. An unbounded number of
	//  message elements is allowed.
	// -----------------------------------------------------------------------

	DOMElement *resultMessage = XmlCommon::CreateElement(this->resultDocument, "oval_results:message", msg);

	// add the message as a child element
	if(resultTest->hasChildNodes()) {
		// make sure it is inserted before the tested object
		DOMNode *testedObj = XmlCommon::FindNode(resultTest, "definition_object");		
		resultTest->insertBefore(resultMessage, testedObj);
	} else {
		resultTest->appendChild(resultMessage);
	}
}

void OvalResultXml::AddTestedObject(DOMElement *resultTest, DOMElement *itemObj, string result, string objectId)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	If the provided item has a object section add it to the result test
	//	as a tested object and copy all the children of the tested item's object
	//	section tot he result file. If no object section is found create an 
	//	empty object record with only the result and the object id set on the
	//	new tested_object element.
	// -----------------------------------------------------------------------

	DOMElement *resultTestedObject = NULL;

	if(itemObj != NULL) {

		// Copy the object section to the result test
		resultTestedObject = CopyElement((DOMElement*)itemObj);

		// Rename the object section to tested_object
		resultTestedObject = (DOMElement*)resultDocument->renameNode(resultTestedObject, NULL, XMLString::transcode("tested_object"));

	} else {

		// Create an empty object element
		resultTestedObject = XmlCommon::CreateElement(this->resultDocument, "tested_object");
	}

	// Add the result attribute to the tested object element
	XmlCommon::AddAttribute(resultTestedObject, "result", result);

	// Add the object id to the tested object element
	XmlCommon::AddAttribute(resultTestedObject, "object_id", objectId);

	// Set the tested object as a child of the test node
	resultTest->appendChild(resultTestedObject);
}

void OvalResultXml::AddUnknownTest(string testId, string comment)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Insert the unknown test with the specified id and comment into the 
	//	Result document
	//
	// -----------------------------------------------------------------------

	//	Get a reference to the test element in the result document
	DOMNode *tests = XmlCommon::FindNode(resultDocument, "tests");

	//	Create a new unknown test element and add it as a child of tests
	DOMElement *test = resultDocument->createElementNS(XMLString::transcode(this->GetXmlNSForAlias("independent").c_str()), XMLString::transcode("unknown_test"));
	tests->appendChild(test);

	//	Set the attributes on the on test element
	XmlCommon::AddAttribute(test, "id", testId);
	XmlCommon::AddAttribute(test, "comment", comment);
	XmlCommon::AddAttribute(test, "result", "-1");

	// Add the independant namespace to the results document
	this->UpdateNamespaceInfo("independent");

	// Add the version to the test
	// NOTE: this is hard coded for this reference implementation
	// This implementation does not support analyzing tests with 
	// variables with different values. Version is only needed
	// if a test used variables and the varialbes are different
	// for each use of the test in a set of definitions
	XmlCommon::AddAttribute(test, "version", "1");
}

XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* OvalResultXml::GetResultFile()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the resultDocument
	// -----------------------------------------------------------------------

	return resultDocument;
}

void OvalResultXml::SetCriterionParentResult(DOMElement *resultDefinition, string type, string criterionResult)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the result on either the software or the configuration element
	//	for the specified definition
	//
	// -----------------------------------------------------------------------

	// Get the parent of the criterion
	DOMNode *criterionParent = NULL;
	if(type.compare("software") == 0) {
		criterionParent = XmlCommon::FindNode(resultDefinition, "software");
	} else if(type.compare("configuration") == 0) {
		criterionParent = XmlCommon::FindNode(resultDefinition, "configuration");
	} else {
		throw OvalResultXmlException("Error: An invalide criterion type was specified: " + type + ".");
	}

	SetResult((DOMElement*)criterionParent, criterionResult);

}
void OvalResultXml::SetResult(DOMElement *elm, string result)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the result attribute for the element
	// -----------------------------------------------------------------------

	// First check if the element already has a result attribute.
	// and remove it.
	DOMAttr *attributeNode = elm->getAttributeNode(XMLString::transcode("result"));
	if(attributeNode != NULL) {
		elm->removeAttributeNode(attributeNode);
		attributeNode->release();
	}
    
	// Next add the new result attribute
	XmlCommon::AddAttribute(elm, "result", result);
}

// ***************************************************************************************	//
//								Private members												//
// ***************************************************************************************	//
void OvalResultXml::AddDefinitionData(DOMElement *resultTest, DOMElement *definitionData)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add the the provided definition data section to the provided results
	//	test
	// -----------------------------------------------------------------------

	// Copy the element recursively
	DOMNode *resultDefinitionData = CopyElement(definitionData);
	
	// Rename the data element
	resultDefinitionData = resultDocument->renameNode(resultDefinitionData, NULL, XMLString::transcode("definition_data"));
	
	// Set the data as a child of the test node
	resultTest->appendChild(resultDefinitionData);
}

void OvalResultXml::AddDefinitionObject(DOMElement *resultTest, DOMElement *definitionObject)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add the the provided definition object section to the provided results
	//	test
	// -----------------------------------------------------------------------

	// Copy the element recursively
	DOMNode *resultDefinitionObject = CopyElement(definitionObject);
	
	// Rename the object element
	resultDefinitionObject = resultDocument->renameNode(resultDefinitionObject, NULL, XMLString::transcode("definition_object"));
	
	// Set the object as a child of the test node
	resultTest->appendChild(resultDefinitionObject);
}

void OvalResultXml::AddGenerators(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *ovalDoc, XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *dataDoc)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add the generators element to the result document.
	//	Copy the generator eleents from the oval document and the data 
	//	document. Create the generator element for the results document
	// -----------------------------------------------------------------------

	// Get the oval_results node
	DOMElement *orNode = XmlCommon::FindNode(this->resultDocument, "oval_results");

	// Create the Generators node
	DOMElement *generators = XmlCommon::AddChildElement(this->resultDocument, orNode, "generators");
	
	// oval generator
	//
	// Get the oval generator element in the oval doc
	DOMElement *defOvalGenerator = XmlCommon::FindNode(ovalDoc, "generator");

	// copy the generators from the oval doc

	// Get the timestamp and schema version from the oval generator
	string ts = XmlCommon::GetDataNodeValue(XmlCommon::FindNode((DOMElement*)defOvalGenerator, "timestamp"));
	string schemaVersion = XmlCommon::GetDataNodeValue(XmlCommon::FindNode((DOMElement*)defOvalGenerator, "schema_version"));

	// Create the corresponding result document nodes
	DOMElement *ovGeneratorElm = XmlCommon::AddChildElement(resultDocument, generators, "oval");
	XmlCommon::AddChildElement(this->resultDocument, ovGeneratorElm, "schema_version", schemaVersion);
	XmlCommon::AddChildElement(this->resultDocument, ovGeneratorElm, "timestamp", ts);

	// system_characteristics generator
	//
	// Get the data generator element in the data doc
	DOMElement *dataGenerator = XmlCommon::FindNode(dataDoc, "generator");

	// import the data generator node 
	DOMElement *resultDataGen = CopyElement((DOMElement*)dataGenerator);

	// Rename the data generator element
	resultDataGen = (DOMElement*)resultDocument->renameNode(resultDataGen, NULL, XMLString::transcode("system_characteristics"));

	// Set the data generator as a child of the generators node
	generators->appendChild(resultDataGen);	

	// oval-results generator
	//
	// Get a time stamp
	string time = Common::GetTimeStamp();

	DOMElement *orGeneratorElm = XmlCommon::AddChildElement(resultDocument, generators, "results");
	XmlCommon::AddChildElement(this->resultDocument, orGeneratorElm, "product_name", "OVAL Definition Interpreter");
	XmlCommon::AddChildElement(this->resultDocument, orGeneratorElm, "product_version", Version::GetVersion());
	XmlCommon::AddChildElement(this->resultDocument, orGeneratorElm, "schema_version", "4");
	XmlCommon::AddChildElement(this->resultDocument, orGeneratorElm, "timestamp", time);	
}

void OvalResultXml::AddSystemInfo(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *dataDoc)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Add the system_info element to the result document.
	//	Copy the element from the data document
	// -----------------------------------------------------------------------

	// Get the oval_results node
	DOMNode *orNode = XmlCommon::FindNode(resultDocument, "oval_results");

	// Get the system_info element in the data doc
	DOMNode *dataSysInfo = XmlCommon::FindNode(dataDoc, "system_info");

	// Copy the system_info node 
	DOMNode *resultSysInfo = CopyElement((DOMElement*)dataSysInfo);

	// Set the new nodes parent to the oval_results element
	orNode->appendChild(resultSysInfo);	
}

DOMElement* OvalResultXml::CopyElement(DOMElement *srcNode, bool useFamilyNS, string familyXMLNS)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Recursively copy the specified node. Return the new copied node
	// -----------------------------------------------------------------------

	// Get the node's name
	string nodeName = XmlCommon::GetElementName(srcNode);

	// create a new node with the same name as the source
	DOMNode *newNode = NULL;
	if(useFamilyNS) {
		newNode = this->resultDocument->createElementNS(XMLString::transcode(familyXMLNS.c_str()), XMLString::transcode(nodeName.c_str()));
	} else {
		newNode = this->resultDocument->createElement(XMLString::transcode(nodeName.c_str()));
	}

	// Copy attributes
	DOMNamedNodeMap *attributesNNM = srcNode->getAttributes();
	unsigned int attIndex = 0;
	while(attIndex < attributesNNM->getLength()) {
		DOMNode *attNode = attributesNNM->item(attIndex);
		
		// Get the attributes name and value
		string attName = XmlCommon::GetElementName((DOMElement*)attNode);
		string attValue = XmlCommon::GetAttributeByName(srcNode, attName);

		// Add the new attribute
		XmlCommon::AddAttribute((DOMElement*)newNode, attName, attValue);

		attIndex++;
	}

	// Check for child nodes
	if(XmlCommon::HasChildElements(srcNode)) {

		DOMNodeList *srcChildList = srcNode->getChildNodes();
		unsigned int index = 0;
		while(index < srcChildList->getLength()) {

			DOMNode *child = srcChildList->item(index++);

			//	Only consider ELEMENT_NODES
			if(child->getNodeType() == DOMNode::ELEMENT_NODE) {
				
				// Make recursive call
				DOMNode *childCopy = CopyElement((DOMElement*)child);
				
				// Add result as a child of the new node
				newNode->appendChild(childCopy);
			}
		}
	} else {
		// Copy the node's value
		try {

			string srcValue = XmlCommon::GetDataNodeValue(srcNode);
			if(srcValue.compare("") != 0) {
				DOMText *tmpTextNode = this->resultDocument->createTextNode(XMLString::transcode(srcValue.c_str()));
				newNode->appendChild(tmpTextNode);
			}

		} catch(...) {/* ignore this error */}
	}
	
	return (DOMElement*)newNode;
}

DOMElement* OvalResultXml::CreateNodeWithValue(DOMElement *parent, string name, string value)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Create a new DOMElement named "name" add to it a new DOMText node 
	//	with value "value' and add the new DOMElement as a child of parent
	// -----------------------------------------------------------------------

	//	Create the new node
	DOMElement *newNode = (DOMElement*)XmlCommon::CreateElement(this->resultDocument, name, value);
		
	//	Append it as a child of parent
	parent->appendChild(newNode);

	return newNode;
}

void OvalResultXml::UpdateNamespaceInfo(string ovalXmlnsAlias)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Update the namespace and schema location on the document root with 
	//	the specified namespace.
	// -----------------------------------------------------------------------

	string resultXmlnsAlias = ovalXmlnsAlias;	// assumes that the namespace aliases are always going to be the same in oval and oval_results
	string resultXmlns = this->GetXmlNSForAlias(resultXmlnsAlias);
	string resultSchemaLocation = this->GetSchemaLocationForAlias(resultXmlnsAlias);
/*
	if (resultXmlnsAlias.compare(OvalResultXml::OVALRESULTSALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS;
		resultSchemaLocation = OvalResultXml::OVALRESULTSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::WINDOWSALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::WINDOWSALIAS;
		resultSchemaLocation = OvalResultXml::WINDOWSSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::DEBIANALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::DEBIANALIAS;
		resultSchemaLocation = OvalResultXml::DEBIANSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::INDEPENDENTALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::INDEPENDENTALIAS;
		resultSchemaLocation = OvalResultXml::INDEPENDENTSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::IOSALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::IOSALIAS;
		resultSchemaLocation = OvalResultXml::IOSSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::MACOSALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::MACOSALIAS;
		resultSchemaLocation = OvalResultXml::MACOSSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::REDHATALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::REDHATALIAS;
		resultSchemaLocation = OvalResultXml::REDHATSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::SOLARISALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::SOLARISALIAS;
		resultSchemaLocation = OvalResultXml::SOLARISSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::UNIXALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::UNIXALIAS;
		resultSchemaLocation = OvalResultXml::UNIXSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::XMLSIGALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::XMLSIGALIAS;
		resultSchemaLocation = OvalResultXml::XMLSIGSCHEMALOCATION;
	}
	*/

	// check if the namespace has been added
	DOMElement *ovalResultsDocNode = XmlCommon::FindNode(this->resultDocument, "oval_results");
	if(XmlCommon::GetAttributeByName(ovalResultsDocNode, "xmlns:" + resultXmlnsAlias).compare("") == 0) {
		XmlCommon::AddAttribute((DOMElement*)ovalResultsDocNode, "xmlns:" + resultXmlnsAlias, resultXmlns);
		// add the schema location
		string schemaLocation = XmlCommon::GetAttributeByName(ovalResultsDocNode, "xsi:schemaLocation");
		if(schemaLocation.length() > 0) {
			schemaLocation = schemaLocation + " ";
		}
		schemaLocation = schemaLocation + resultSchemaLocation;
		XmlCommon::AddAttribute((DOMElement*)ovalResultsDocNode, "xsi:schemaLocation", schemaLocation);
	}
}

string OvalResultXml::GetXmlNSForAlias(string resultXmlnsAlias) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Convert the specified xml namespace alias to the full namespace uri
	// -----------------------------------------------------------------------

	string resultXmlns = "";

	if (resultXmlnsAlias.compare(OvalResultXml::OVALRESULTSALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::WINDOWSALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::WINDOWSALIAS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::DEBIANALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::DEBIANALIAS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::INDEPENDENTALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::INDEPENDENTALIAS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::IOSALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::IOSALIAS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::MACOSALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::MACOSALIAS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::REDHATALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::REDHATALIAS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::SOLARISALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::SOLARISALIAS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::UNIXALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::UNIXALIAS;
	} else if (resultXmlnsAlias.compare(OvalResultXml::XMLSIGALIAS) == 0) {
		resultXmlns = OvalResultXml::OVALRESULTSNS + "#" + OvalResultXml::XMLSIGALIAS;
	}

	return resultXmlns;
}

string OvalResultXml::GetSchemaLocationForAlias(string resultXmlnsAlias) {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Convert the specified xml namespace alias to the scheam location
	// -----------------------------------------------------------------------

	string resultSchemaLocation = "";

	if (resultXmlnsAlias.compare(OvalResultXml::OVALRESULTSALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::OVALRESULTSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::WINDOWSALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::WINDOWSSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::DEBIANALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::DEBIANSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::INDEPENDENTALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::INDEPENDENTSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::IOSALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::IOSSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::MACOSALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::MACOSSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::REDHATALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::REDHATSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::SOLARISALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::SOLARISSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::UNIXALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::UNIXSCHEMALOCATION;
	} else if (resultXmlnsAlias.compare(OvalResultXml::XMLSIGALIAS) == 0) {
		resultSchemaLocation = OvalResultXml::XMLSIGSCHEMALOCATION;
	}

	return this->GetXmlNSForAlias(resultXmlnsAlias) + " " + resultSchemaLocation;
}

//****************************************************************************************//
//							OvalResultXmlException Class								  //	
//****************************************************************************************//
OvalResultXmlException::OvalResultXmlException(string errMsgIn, int severity) : Exception(errMsgIn, severity)
{
	// -----------------------------------------------------------------------
	//	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.
	//
	// -----------------------------------------------------------------------

}

OvalResultXmlException::~OvalResultXmlException()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------

}

