//
// $Id: XmlFileContentData.cpp,v 1.4 2005/08/05 20:19:38 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 "XmlFileContentData.h"

//****************************************************************************************//
//								FileData Class											  //	
//****************************************************************************************//
XmlFileContentData::XmlFileContentData(DOMElement *test) : AbsXmlFileContentData(test)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Initialize a new AbsXmlFileContentData and populate with the node's data
	// -----------------------------------------------------------------------

	//	Call the parse node function
	ParseNode(test);
}

XmlFileContentData::XmlFileContentData(): AbsXmlFileContentData()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Initialize a new AbsXmlFileContentData as an empty object.
	// -----------------------------------------------------------------------
}

XmlFileContentData::~XmlFileContentData()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Delete data members
	// -----------------------------------------------------------------------

}

// ***************************************************************************************	//
//								Private members												//
// ***************************************************************************************	//
void XmlFileContentData::ParseNode(DOMElement *test)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Parse a test node. Set all data elements for this FileData
	//	object.
	//	
	// -----------------------------------------------------------------------

	// Retreive the test id from the DOMNode.
	testId = XmlCommon::GetAttributeByName(test, "id");
	if (testId.compare("") == 0) {
		throw ProbeDataException("Error: Unable to find the 'id' attribute for specified the test.");
	}

	///////////////////////////////////////////////////////////////////////////
	//	Parse the node
	///////////////////////////////////////////////////////////////////////////
	// Get the object element
	DOMElement *object = XmlCommon::FindNodeNS(test, "object");
	if (object == NULL) {
		throw new ProbeDataException("Error: Unable to locate object section for test: " + testId + "\n");
	}

	// Get the path element - path is required
	DOMElement *pathNode = XmlCommon::FindNodeNS(object, "path");
	if (object == NULL) {
		throw new ProbeDataException("Error: Unable to locate path elemen for test: " + testId + "\n");
	}

	// get the operator for path
	string pathOperator = XmlCommon::GetAttributeByName(pathNode, "operator");
	if(pathOperator.compare("pattern match") == 0){
		path->type = pattern_match;
		this->isPatternMatchObject = true;
	} else {
		path->type = literal;
	}


	// Get the components and their types
	string componentType	= "";
	string componentValue	= "";

	REGEX myMatcher;
	DOMNodeList *pathChildren = pathNode->getChildNodes();
	unsigned int index = 0;
	while(index < pathChildren->getLength()) {

		DOMNode *tmpNode = pathChildren->item(index);

		//	only concerned with ELEMENT_NODEs
		if (tmpNode->getNodeType() == DOMNode::ELEMENT_NODE) {
			DOMElement* pathChild = (DOMElement*)tmpNode;

			componentValue = XmlCommon::GetDataNodeValue(pathChild);
			componentType = XmlCommon::GetAttributeByName(pathChild, "type");
			
			if(componentType.compare("literal") == 0) {
				
				// do nothing for now
				
			} else if(componentType.compare("environment_variable") == 0) {

				componentValue = EnvironmentVariableProbe::GetEnvironmentVariableValue(componentValue);

			} else if(componentType.compare("registry_value") == 0) {

				componentValue = RegistryProbe::GetRegKeyValue(componentValue);				
			}

			//	Build the file path
			path->object.append(componentValue);
		}
		index ++;
	}

	// Get the xpath element - path is required
	DOMElement *xpathNode = XmlCommon::FindNodeNS(object, "xpath");
	if (object == NULL) {
		throw new ProbeDataException("Error: Unable to locate xpath element for test: " + testId + "\n");
	}
    
	// get the operator for xpath
	string xpathOperator = XmlCommon::GetAttributeByName(xpathNode, "operator");
	if(xpathOperator.compare("pattern match") == 0){
		xpath->type = pattern_match;
		this->isPatternMatchObject = true;
	} else {
		xpath->type = literal;
	}

	// validate the datatype for xpath
	string xpathDatatype = XmlCommon::GetAttributeByName(xpathNode, "datatype");
	if(xpathDatatype.compare("string") == 0 || xpathDatatype.compare("") == 0) {
		//
	} else {
		throw new ProbeDataException("Error: Invalid datatype for xpath element found: " + xpathDatatype + " in test: " + testId + "\n");
	}

	// get the value for xpath
	string xpathValue = XmlCommon::GetDataNodeValue(xpathNode);
	if(xpathValue.compare("") == 0){
		throw new ProbeDataException("Error: No xpath expression found for test: " + testId + "\n");
	} else {
		xpath->object = xpathValue;
	}
}
