<commit_before>/*
 * Copyright 2012--2014 Red Hat Inc., Durham, North Carolina.
 * All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Authors:
 *      <NAME> <<EMAIL>>
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "public/scap_ds.h"
#include "public/oscap_text.h"
#include "public/oscap.h"

#include "common/alloc.h"
#include "common/_error.h"
#include "common/util.h"
#include "common/list.h"

#include "ds_common.h"
#include "rds_priv.h"
#include "source/public/oscap_source.h"
#include "source/oscap_source_priv.h"

#include <sys/stat.h>
#include <time.h>
#include <libgen.h>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

static const char* arf_ns_uri = "http://scap.nist.gov/schema/asset-reporting-format/1.1";
static const char* core_ns_uri = "http://scap.nist.gov/schema/reporting-core/1.1";
static const char* arfvocab_ns_uri = "http://scap.nist.gov/specifications/arf/vocabulary/relationships/1.0#";
static const char* arfrel_ns_uri = "http://scap.nist.gov/vocabulary/arf/relationships/1.0#";
static const char* ai_ns_uri = "http://scap.nist.gov/schema/asset-identification/1.1";

static xmlNodePtr _lookup_container_in_arf(xmlDocPtr doc, const char *container_name)
{
	xmlNodePtr root = xmlDocGetRootElement(doc);
	xmlNodePtr ret = NULL;
	xmlNodePtr candidate = root->children;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (strcmp((const char*)(candidate->name), container_name) == 0) {
			ret = candidate;
			break;
		}
	}

	return ret;
}

static xmlNodePtr _lookup_report_in_arf(xmlDocPtr doc, const char *report_id)
{
	xmlNodePtr container = _lookup_container_in_arf(doc, "reports");
	xmlNodePtr component = NULL;
	xmlNodePtr candidate = container->children;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (strcmp((const char*)(candidate->name), "report") != 0)
			continue;

		char* candidate_id = (char*)xmlGetProp(candidate, BAD_CAST "id");
		if (strcmp(candidate_id, report_id) == 0)
		{
			component = candidate;
			xmlFree(candidate_id);
			break;
		}
		xmlFree(candidate_id);
	}

	return component;
}

static xmlNodePtr _lookup_request_in_arf(xmlDocPtr doc, const char *request_id)
{
	xmlNodePtr container = _lookup_container_in_arf(doc, "report-requests");
	xmlNodePtr component = NULL;
	xmlNodePtr candidate = container->children;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (strcmp((const char*)(candidate->name), "report-request") != 0)
			continue;

		char* candidate_id = (char*)xmlGetProp(candidate, BAD_CAST "id");
		if (request_id == NULL || strcmp(candidate_id, request_id) == 0)
		{
			component = candidate;
			xmlFree(candidate_id);
			break;
		}
		xmlFree(candidate_id);
	}

	return component;
}

static xmlNodePtr ds_rds_get_inner_content(xmlDocPtr doc, xmlNodePtr parent_node)
{
	xmlNodePtr candidate = parent_node->children;
	xmlNodePtr content_node = NULL;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (strcmp((const char*)(candidate->name), "content") == 0) {
			content_node = candidate;
			break;
		}
	}

	if (!content_node) {
		oscap_seterr(OSCAP_EFAMILY_XML, "Given ARF node has no 'arf:content' node inside!");
		return NULL;
	}

	return content_node;
}

static int ds_rds_dump_arf_content(xmlDocPtr doc, xmlNodePtr parent_node, const char* target_file)
{
	xmlNodePtr content_node = ds_rds_get_inner_content(doc, parent_node);

	if (!content_node)
		return -1;

	xmlNodePtr candidate = content_node->children;
	xmlNodePtr inner_root = NULL;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (inner_root) {
			oscap_seterr(OSCAP_EFAMILY_XML, "There are multiple nodes inside an 'arf:content' node. "
				"Only the last one will be used!");
		}

		inner_root = candidate;
	}

	// We assume that arf:content is XML. This is reasonable because both
	// reports and report requests are XML documents.

	xmlDoc *new_doc = ds_doc_from_foreign_node(inner_root, doc);
	if (xmlSaveFileEnc(target_file, new_doc, "utf-8") == -1)
	{
		oscap_seterr(OSCAP_EFAMILY_GLIBC, "Error when saving resulting DOM to file '%s' while dumping arf content.", target_file);
		xmlFreeDoc(new_doc);
		return -1;
	}
	xmlFreeDoc(new_doc);

	return 0;
}

int ds_rds_decompose(const char* input_file, const char* report_id, const char* request_id, const char* target_dir)
{
	struct oscap_source *rds_source = oscap_source_new_from_file(input_file);
	xmlDocPtr doc = oscap_source_get_xmlDoc(rds_source);

	if (!doc) {
		oscap_source_free(rds_source);
		return -1;<commit_msg>Use oscap_source to save arf components (arf:content)<commit_after>/*
 * Copyright 2012--2014 Red Hat Inc., Durham, North Carolina.
 * All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Authors:
 *      <NAME> <<EMAIL>>
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "public/scap_ds.h"
#include "public/oscap_text.h"
#include "public/oscap.h"

#include "common/alloc.h"
#include "common/_error.h"
#include "common/util.h"
#include "common/list.h"

#include "ds_common.h"
#include "rds_priv.h"
#include "source/public/oscap_source.h"
#include "source/oscap_source_priv.h"

#include <sys/stat.h>
#include <time.h>
#include <libgen.h>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

static const char* arf_ns_uri = "http://scap.nist.gov/schema/asset-reporting-format/1.1";
static const char* core_ns_uri = "http://scap.nist.gov/schema/reporting-core/1.1";
static const char* arfvocab_ns_uri = "http://scap.nist.gov/specifications/arf/vocabulary/relationships/1.0#";
static const char* arfrel_ns_uri = "http://scap.nist.gov/vocabulary/arf/relationships/1.0#";
static const char* ai_ns_uri = "http://scap.nist.gov/schema/asset-identification/1.1";

static xmlNodePtr _lookup_container_in_arf(xmlDocPtr doc, const char *container_name)
{
	xmlNodePtr root = xmlDocGetRootElement(doc);
	xmlNodePtr ret = NULL;
	xmlNodePtr candidate = root->children;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (strcmp((const char*)(candidate->name), container_name) == 0) {
			ret = candidate;
			break;
		}
	}

	return ret;
}

static xmlNodePtr _lookup_report_in_arf(xmlDocPtr doc, const char *report_id)
{
	xmlNodePtr container = _lookup_container_in_arf(doc, "reports");
	xmlNodePtr component = NULL;
	xmlNodePtr candidate = container->children;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (strcmp((const char*)(candidate->name), "report") != 0)
			continue;

		char* candidate_id = (char*)xmlGetProp(candidate, BAD_CAST "id");
		if (strcmp(candidate_id, report_id) == 0)
		{
			component = candidate;
			xmlFree(candidate_id);
			break;
		}
		xmlFree(candidate_id);
	}

	return component;
}

static xmlNodePtr _lookup_request_in_arf(xmlDocPtr doc, const char *request_id)
{
	xmlNodePtr container = _lookup_container_in_arf(doc, "report-requests");
	xmlNodePtr component = NULL;
	xmlNodePtr candidate = container->children;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (strcmp((const char*)(candidate->name), "report-request") != 0)
			continue;

		char* candidate_id = (char*)xmlGetProp(candidate, BAD_CAST "id");
		if (request_id == NULL || strcmp(candidate_id, request_id) == 0)
		{
			component = candidate;
			xmlFree(candidate_id);
			break;
		}
		xmlFree(candidate_id);
	}

	return component;
}

static xmlNodePtr ds_rds_get_inner_content(xmlDocPtr doc, xmlNodePtr parent_node)
{
	xmlNodePtr candidate = parent_node->children;
	xmlNodePtr content_node = NULL;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (strcmp((const char*)(candidate->name), "content") == 0) {
			content_node = candidate;
			break;
		}
	}

	if (!content_node) {
		oscap_seterr(OSCAP_EFAMILY_XML, "Given ARF node has no 'arf:content' node inside!");
		return NULL;
	}

	return content_node;
}

static int ds_rds_dump_arf_content(xmlDocPtr doc, xmlNodePtr parent_node, const char* target_file)
{
	xmlNodePtr content_node = ds_rds_get_inner_content(doc, parent_node);

	if (!content_node)
		return -1;

	xmlNodePtr candidate = content_node->children;
	xmlNodePtr inner_root = NULL;

	for (; candidate != NULL; candidate = candidate->next)
	{
		if (candidate->type != XML_ELEMENT_NODE)
			continue;

		if (inner_root) {
			oscap_seterr(OSCAP_EFAMILY_XML, "There are multiple nodes inside an 'arf:content' node. "
				"Only the last one will be used!");
		}

		inner_root = candidate;
	}

	// We assume that arf:content is XML. This is reasonable because both
	// reports and report requests are XML documents.
	xmlDoc *new_doc = ds_doc_from_foreign_node(inner_root, doc);
	struct oscap_source *source = oscap_source_new_from_xmlDoc(new_doc, target_file);
	int ret = oscap_source_save_as(source, NULL);
	oscap_source_free(source);
	return ret;
}

int ds_rds_decompose(const char* input_file, const char* report_id, const char* request_id, const char* target_dir)
{
	struct oscap_source *rds_source = oscap_source_new_from_file(input_file);
	xmlDocPtr doc = oscap_source_get_xmlDoc(rds_source);

	if (!doc) {
		oscap_source_free(rds_source);
		return -1;
{'fraction_non_alphanumeric': 0.11853583955391672, 'fraction_numerical': 0.007914380789639356, 'mean_word_length': 4.720164609053498, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 82}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1399286', 'n_tokens_mistral': 4090, 'n_tokens_neox': 3809, 'n_words': 992}