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

#include <string.h>

#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>

#include "public/cvrf.h"
#include "cvrf_priv.h"

#include "common/list.h"
#include "common/_error.h"
#include "common/xmltext_priv.h"
#include "common/elements.h"
#include "common/oscap_string.h"
#include "common/util.h"

#include "CPE/cpelang_priv.h"
#include "CPE/public/cpe_dict.h"
#include "CVSS/cvss_priv.h"
#include "CVSS/public/cvss_score.h"

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

#include "OVAL/public/oval_system_characteristics.h"
#include "OVAL/public/oval_definitions.h"
#include "OVAL/adt/oval_string_map_impl.h"
#include "OVAL/public/oval_types.h"
#include "OVAL/public/oval_probe_session.h"
#include "OVAL/public/oval_probe.h"
#include "OVAL/oval_definitions_impl.h"


/*****************************************************************************
 * Structure definitions
 */

struct cvrf_model_eval {
	char *os_name;
	char *os_version;
	struct oscap_stringlist *product_ids;
	struct cvrf_model *model;
	struct oval_definition_model *def_model;
};
OSCAP_ACCESSOR_STRING(cvrf_model_eval, os_name);
OSCAP_ACCESSOR_STRING(cvrf_model_eval, os_version);

struct oscap_string_iterator *cvrf_model_eval_get_product_ids(struct cvrf_model_eval *eval) {
	return oscap_stringlist_get_strings(eval->product_ids);
}
struct cvrf_model *cvrf_eval_get_model(struct cvrf_model_eval *eval) {
	return eval->model;
}
void cvrf_eval_set_model(struct cvrf_model_eval *eval, struct cvrf_model *model) {
	eval->model = model;
}

struct cvrf_model_eval *cvrf_model_eval_new() {
	struct cvrf_model_eval *ret;

	ret = oscap_alloc(sizeof(struct cvrf_model_eval));
	if (ret == NULL)
		return NULL;

	ret->os_name = NULL;
	ret->os_version = NULL;
	ret->product_ids = oscap_stringlist_new();
	ret->model = cvrf_model_new();
	ret->def_model = oval_definition_model_new();

	return ret;
}

void cvrf_model_eval_free(struct cvrf_model_eval *eval) {

	if (eval == NULL)
		return;

	oscap_free(eval->os_name);
	oscap_free(eval->os_version);
	oscap_stringlist_free(eval->product_ids);
	cvrf_model_free(eval->model);
	oval_definition_model_free(eval->def_model);
	oscap_free(eval);
}



struct cvrf_rpm_attributes {
	char *full_package_name;
	char *rpm_name;
	char *rpm_version;
	char *rpm_release;
	char *rpm_architecture;
	char *evr_format;
};
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, full_package_name)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, rpm_name)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, rpm_version)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, rpm_release)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, rpm_architecture)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, evr_format)


struct cvrf_rpm_attributes *cvrf_rpm_attributes_new() {
	struct cvrf_rpm_attributes *ret;

	ret = oscap_alloc(sizeof(struct cvrf_rpm_attributes));
	if (ret == NULL)
		return NULL;

	ret->full_package_name = NULL;
	ret->rpm_name = NULL;
	ret->rpm_version = NULL;
	ret->rpm_release = NULL;
	ret->rpm_architecture = NULL;
	ret->evr_format = NULL;

	return ret;
}

void cvrf_rpm_attributes_free(struct cvrf_rpm_attributes *attributes) {

	if (attributes == NULL)
		return;

	oscap_free(attributes->full_package_name);
	oscap_free(attributes->rpm_name);
	oscap_free(attributes->rpm_version);
	oscap_free(attributes->rpm_release);
	oscap_free(attributes->rpm_architecture);
	oscap_free(attributes->evr_format);
	oscap_free(attributes);
}

/*
 * End of structure definitions
 *****************************************************************************/


#define TAG_CVRF_DOC BAD_CAST "cvrfdoc"
#define ATTR_PRODUCT_ID "ProductID"
//namespaces
#define CVRF_NS BAD_CAST "http://www.icasi.org/CVRF/schema/cvrf/1.1"
#define VULN_NS BAD_CAST "http://www.icasi.org/CVRF/schema/vuln/1.1"


static const char *get_cvrf_product_id_from_branch(struct cvrf_model_eval *eval, struct cvrf_branch *branch) {

	const char *product_id = NULL;
	const char *os_name = cvrf_model_eval_get_os_name(eval);
	struct cvrf_branch *subbranch;
	struct cvrf_product_name *full_name;

	if (cvrf_branch_get_branch_type(branch) == CVRF_BRANCH_PRODUCT_FAMILY) {
		struct oscap_iterator *subbranches = cvrf_branch_get_subbranches(branch);

		while(oscap_iterator_has_more(subbranches)) {
			subbranch = oscap_iterator_next(subbranches);
			product_id = get_cvrf_product_id_from_branch(eval, subbranch);

			if (product_id != NULL)
				break;
		}
		oscap_iterator_free(subbranches);
		return product_id;
	}
	else {
		if (!strcmp(cvrf_branch_get_branch_name(branch), os_name)) {
			full_name = cvrf_branch_get_cvrf_product_name(branch);
			product_id = cvrf_product_name_get_product_id(full_name);
			return product_id;
		}
	}
	return product_id;
}

static void find_all_cvrf_product_ids_by_OS(struct cvrf_model_eval *eval, struct cvrf_model *model) {

	const char *branch_product_id = NULL;
	const char *relation_product_id = NULL;
	struct cvrf_product_tree *tree = cvrf_model_get_product_tree(model);
	struct cvrf_relationship *relation;
	struct cvrf_product_name *full_name;
	struct cvrf_branch *branch;

	struct oscap_iterator *branches = cvrf_product_tree_get_branches(tree);
	while (oscap_iterator_has_more(branches)) {
		branch = oscap_iterator_next(branches);
		branch_product_id = get_cvrf_product_id_from_branch(eval, branch);

		if (branch_product_id != NULL)
			break;
	}
	oscap_iterator_free(branches);
	printf("Branch Product ID: %s\n", branch_product_id);
	if (branch_product_id == NULL)
		return;


	struct cvrf_relationship_iterator *relationships = cvrf_product_tree_get_relationships(tree);
	while (cvrf_relationship_iterator_has_more(relationships)) {
		relation = cvrf_relationship_iterator_next(relationships);
		if (!strcmp(branch_product_id, cvrf_relationship_get_relates_to_ref(relation))) {
			full_name = cvrf_relationship_get_product_name(relation);
			relation_product_id = cvrf_product_name_get_product_id(full_name);
			printf("Relation Product ID: %s\n", relation_product_id);
			oscap_stringlist_add_string(eval->product_ids, relation_product_id);
		}
	}
	cvrf_relationship_iterator_free(relationships);
}

void cvrf_export_results(struct oscap_source *import_source, struct oscap_source *export_source, const char *os_name) {
	__attribute__nonnull__(import_source);

	const char *export_file = oscap_source_get_filepath(export_source);
	struct xmlTextWriterPtr *writer = xmlNewTextWriterFilename(export_file, 0);
	if (writer == NULL) {
		oscap_setxmlerr(xmlGetLastError());
		return;
	}

	struct cvrf_model_eval *eval = cvrf_model_eval_new();
	struct cvrf_model *model = cvrf_model_import(import_source);
	cvrf_eval_set_model(eval, model);
	cvrf_model_eval_set_os_name(eval, os_name);
	find_all_cvrf_product_ids_by_OS(eval, model);
	cvrf_model_eval_construct_definition_model(eval);

	struct cvrf_vulnerability_iterator *it = cvrf_model_get_vulnerabilities(model);
	struct cvrf_vulnerability *vuln;
	const char *product_id = NULL;
	bool vulnerable = false;


	xmlTextWriterSetIndent(writer, 1);
	xmlTextWriterSetIndentString(writer, BAD_CAST "  ");
	xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);

	xmlTextWriterStartElementNS(writer, NULL, TAG_CVRF_DOC, CVRF_NS);

	xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "DocumentTitle", NULL);
	xmlTextWriterWriteString(writer, BAD_CAST cvrf_model_get_doc_title(model));
	xmlTextWriterEndElement(writer);

	xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "OS Name", NULL);
	xmlTextWriterWriteString(writer, BAD_CAST os_name);
	xmlTextWriterEndElement(writer);

	xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "Identification", NULL);
	xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "ID", NULL);
	xmlTextWriterWriteString(writer, BAD_CAST cvrf_model_get_identification(model));
	xmlTextWriterEndElement(writer);
	xmlTextWriterEndElement(writer);

	while (cvrf_vulnerability_iterator_has_more(it)) {
		vuln = cvrf_vulnerability_iterator_next(it);
		struct oscap_string_iterator *product_ids = cvrf_model_eval_get_product_ids(eval);

		xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "Vulnerability", VULN_NS);
		xmlTextWriterWriteAttribute(writer, BAD_CAST "Ordinal", BAD_CAST (char *)cvrf_vulnerablity_get_ordinal(vuln));

		if (cvrf_vulnerability_get_cve_id(vuln) != NULL) {
			xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "CVE", NULL);
			xmlTextWriterWriteString(writer, BAD_CAST cvrf_vulnerability_get_cve_id(vuln));
			xmlTextWriterEndElement(writer);
		}

		while (oscap_string_iterator_has_more(product_ids)) {
			product_id = oscap_string_iterator_next(product_ids);

			xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "Result", NULL);
			xmlTextWriterWriteAttribute(writer, ATTR_PRODUCT_ID, BAD_CAST product_id);
			if (cvrf_product_vulnerability_fixed(vuln, product_id)) {
				xmlTextWriterWriteString(writer, BAD_CAST "FIXED");
			}
			else {
				xmlTextWriterWriteString(writer, BAD_CAST "VULNERABLE");
				vulnerable = true;
			}
			xmlTextWriterEndElement(writer);
		}

		if (vulnerable && cvrf_vulnerability_get_remediation_count(vuln) > 0) {
			xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "Remediations", NULL);
			OSCAP_FOREACH(cvrf_remediation, e, cvrf_vulnerability_get_remediations(vuln), cvrf_remediation_export(e, writer);)
			xmlTextWriterEndElement(writer);
		}

		oscap_string_iterator_free(product_ids);
		xmlTextWriterEndElement(writer);
		vulnerable = false;
	}
	cvrf_vulnerability_iterator_free(it);
	xmlTextWriterEndElement(writer);

	xmlTextWriterEndDocument(writer);
	cvrf_model_eval_free(eval);
	oscap_source_free(export_source);
	xmlFreeTextWriter(writer);
	if (xmlGetLastError() != NULL)
		oscap_setxmlerr(xmlGetLastError());
}


static const char *get_rpm_name_from_cvrf_product_id(struct cvrf_model_eval *eval, const char *product_id) {

	const char *rpm_name = NULL;
	struct cvrf_model *model = cvrf_eval_get_model(eval);
	struct cvrf_product_tree *tree = cvrf_model_get_product_tree(model);
	struct cvrf_branch *branch;
	struct cvrf_product_name *full_name;

	struct oscap_iterator *branches = cvrf_product_tree_get_branches(tree);
	while (oscap_iterator_has_more(branches)) {
		branch = oscap_iterator_next(branches);

		if (cvrf_branch_get_branch_type(branch) == CVRF_BRANCH_PRODUCT_VERSION) {
			full_name = cvrf_branch_get_cvrf_product_name(branch);

			if (oscap_str_endswith(product_id, cvrf_product_name_get_product_id(full_name))) {
				rpm_name = cvrf_product_name_get_cpe(full_name);
				break;
			}
		}

	}
	oscap_iterator_free(branches);
	return rpm_name;
}

static struct cvrf_rpm_attributes *parse_rpm_name_into_components(struct cvrf_model_eval *eval, const char *product_id) {

	struct cvrf_rpm_attributes *attributes = cvrf_rpm_attributes_new();
	const char *rpm_name = get_rpm_name_from_cvrf_product_id(eval, product_id);
	attributes->full_package_name = strdup(rpm_name);

	struct oscap_string *rpm_name_suffix = oscap_string_new();
	struct oscap_string *rpm_release = oscap_string_new();
	struct oscap_string *evr_format = oscap_string_new();
	int dashes_size = 1;
	int periods_size = 1;

	char *rpm_name_dup = strdup(rpm_name);
	char **split_by_dashes = oscap_split(rpm_name_dup, "-");
	while (split_by_dashes[dashes_size-1] != NULL)
		dashes_size++;
	for (int index = 0; index < dashes_size-3; index++) {
		oscap_string_append_string(rpm_name_suffix, split_by_dashes[index]);
		if (index < dashes_size-4)
			oscap_string_append_char(rpm_name_suffix, '-');
	}
	attributes->rpm_name = strdup(oscap_string_get_cstr(rpm_name_suffix));
	attributes->rpm_version = strdup(split_by_dashes[dashes_size-3]);

	char **split_by_periods = oscap_split(split_by_dashes[dashes_size-2], ".");
	while (split_by_periods[periods_size-1] != NULL)
		periods_size++;
	for (int index = 0; index < periods_size-3; index++) {
		oscap_string_append_string(rpm_release, split_by_periods[index]);
		if (index < periods_size-4)
			oscap_string_append_char(rpm_release, '.');
	}
	attributes->rpm_release = strdup(oscap_string_get_cstr(rpm_release));
	attributes->rpm_architecture = strdup(split_by_periods[periods_size-3]);

	char *product_id_dup = strdup(product_id);
	char **split_by_colon = oscap_split(product_id_dup, ":");
	char *name_with_epoch = oscap_strdup(split_by_colon[1]);
	int name_length = strlen(attributes->rpm_name);

	if (name_length == strlen(name_with_epoch)) {
		oscap_string_append_char(evr_format, '0');
	} else {
		for (int epoch_index = name_length+1; epoch_index < strlen(name_with_epoch); epoch_index++)
			oscap_string_append_char(evr_format, name_with_epoch[epoch_index]);
	}
	oscap_string_append_char(evr_format, ':');
	oscap_string_append_string(evr_format, attributes->rpm_version);
	oscap_string_append_char(evr_format, '-');
	oscap_string_append_string(evr_format, attributes->rpm_release);

	attributes->evr_format = strdup(oscap_string_get_cstr(evr_format));


	oscap_free(rpm_name_dup);
	oscap_free(product_id_dup);
	oscap_string_free(evr_format);
	oscap_string_free(rpm_name_suffix);
	oscap_string_free(rpm_release);
	return attributes;
}

bool cvrf_product_vulnerability_fixed(struct cvrf_vulnerability *vuln, char *product) {

	struct cvrf_product_status_iterator *it = cvrf_vulnerability_get_cvrf_product_statuses(vuln);
	struct cvrf_product_status *stat;
	struct oscap_string_iterator *product_ids;
	const char *product_id;

	while (cvrf_product_status_iterator_has_more(it)) {
		stat = cvrf_product_status_iterator_next(it);
		product_ids = cvrf_product_status_get_ids(stat);

		while (oscap_string_iterator_has_more(product_ids)) {
			product_id = oscap_string_iterator_next(product_ids);

			if (strcmp(product_id, product)) {
				oscap_string_iterator_free(product_ids);
				cvrf_product_status_iterator_free(it);
				return true;
			}<commit_msg>Narrow scope within functions in cvrf_eval.c<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>

#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>

#include "public/cvrf.h"
#include "cvrf_priv.h"

#include "common/list.h"
#include "common/_error.h"
#include "common/xmltext_priv.h"
#include "common/elements.h"
#include "common/oscap_string.h"
#include "common/util.h"

#include "CPE/cpelang_priv.h"
#include "CPE/public/cpe_dict.h"
#include "CVSS/cvss_priv.h"
#include "CVSS/public/cvss_score.h"

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

#include "OVAL/public/oval_system_characteristics.h"
#include "OVAL/public/oval_definitions.h"
#include "OVAL/adt/oval_string_map_impl.h"
#include "OVAL/public/oval_types.h"
#include "OVAL/public/oval_probe_session.h"
#include "OVAL/public/oval_probe.h"
#include "OVAL/oval_definitions_impl.h"


/*****************************************************************************
 * Structure definitions
 */

struct cvrf_model_eval {
	char *os_name;
	char *os_version;
	struct oscap_stringlist *product_ids;
	struct cvrf_model *model;
	struct oval_definition_model *def_model;
};
OSCAP_ACCESSOR_STRING(cvrf_model_eval, os_name);
OSCAP_ACCESSOR_STRING(cvrf_model_eval, os_version);

struct oscap_string_iterator *cvrf_model_eval_get_product_ids(struct cvrf_model_eval *eval) {
	return oscap_stringlist_get_strings(eval->product_ids);
}
struct cvrf_model *cvrf_eval_get_model(struct cvrf_model_eval *eval) {
	return eval->model;
}
void cvrf_eval_set_model(struct cvrf_model_eval *eval, struct cvrf_model *model) {
	eval->model = model;
}

struct cvrf_model_eval *cvrf_model_eval_new() {
	struct cvrf_model_eval *ret;

	ret = oscap_alloc(sizeof(struct cvrf_model_eval));
	if (ret == NULL)
		return NULL;

	ret->os_name = NULL;
	ret->os_version = NULL;
	ret->product_ids = oscap_stringlist_new();
	ret->model = cvrf_model_new();
	ret->def_model = oval_definition_model_new();

	return ret;
}

void cvrf_model_eval_free(struct cvrf_model_eval *eval) {

	if (eval == NULL)
		return;

	oscap_free(eval->os_name);
	oscap_free(eval->os_version);
	oscap_stringlist_free(eval->product_ids);
	cvrf_model_free(eval->model);
	oval_definition_model_free(eval->def_model);
	oscap_free(eval);
}



struct cvrf_rpm_attributes {
	char *full_package_name;
	char *rpm_name;
	char *rpm_version;
	char *rpm_release;
	char *rpm_architecture;
	char *evr_format;
};
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, full_package_name)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, rpm_name)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, rpm_version)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, rpm_release)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, rpm_architecture)
OSCAP_ACCESSOR_STRING(cvrf_rpm_attributes, evr_format)


struct cvrf_rpm_attributes *cvrf_rpm_attributes_new() {
	struct cvrf_rpm_attributes *ret;

	ret = oscap_alloc(sizeof(struct cvrf_rpm_attributes));
	if (ret == NULL)
		return NULL;

	ret->full_package_name = NULL;
	ret->rpm_name = NULL;
	ret->rpm_version = NULL;
	ret->rpm_release = NULL;
	ret->rpm_architecture = NULL;
	ret->evr_format = NULL;

	return ret;
}

void cvrf_rpm_attributes_free(struct cvrf_rpm_attributes *attributes) {

	if (attributes == NULL)
		return;

	oscap_free(attributes->full_package_name);
	oscap_free(attributes->rpm_name);
	oscap_free(attributes->rpm_version);
	oscap_free(attributes->rpm_release);
	oscap_free(attributes->rpm_architecture);
	oscap_free(attributes->evr_format);
	oscap_free(attributes);
}

/*
 * End of structure definitions
 *****************************************************************************/


#define TAG_CVRF_DOC BAD_CAST "cvrfdoc"
#define ATTR_PRODUCT_ID "ProductID"
//namespaces
#define CVRF_NS BAD_CAST "http://www.icasi.org/CVRF/schema/cvrf/1.1"
#define VULN_NS BAD_CAST "http://www.icasi.org/CVRF/schema/vuln/1.1"


static const char *get_cvrf_product_id_from_branch(struct cvrf_model_eval *eval, struct cvrf_branch *branch) {

	const char *product_id = NULL;
	const char *os_name = cvrf_model_eval_get_os_name(eval);
	struct cvrf_branch *subbranch;
	struct cvrf_product_name *full_name;

	if (cvrf_branch_get_branch_type(branch) == CVRF_BRANCH_PRODUCT_FAMILY) {
		struct oscap_iterator *subbranches = cvrf_branch_get_subbranches(branch);

		while(oscap_iterator_has_more(subbranches)) {
			subbranch = oscap_iterator_next(subbranches);
			product_id = get_cvrf_product_id_from_branch(eval, subbranch);

			if (product_id != NULL)
				break;
		}
		oscap_iterator_free(subbranches);
		return product_id;
	}
	else {
		if (!strcmp(cvrf_branch_get_branch_name(branch), os_name)) {
			full_name = cvrf_branch_get_cvrf_product_name(branch);
			product_id = cvrf_product_name_get_product_id(full_name);
			return product_id;
		}
	}
	return product_id;
}

static void find_all_cvrf_product_ids_by_OS(struct cvrf_model_eval *eval, struct cvrf_model *model) {

	const char *branch_product_id = NULL;
	const char *relation_product_id = NULL;
	struct cvrf_product_tree *tree = cvrf_model_get_product_tree(model);
	struct cvrf_relationship *relation;
	struct cvrf_product_name *full_name;
	struct cvrf_branch *branch;

	struct oscap_iterator *branches = cvrf_product_tree_get_branches(tree);
	while (oscap_iterator_has_more(branches)) {
		branch = oscap_iterator_next(branches);
		branch_product_id = get_cvrf_product_id_from_branch(eval, branch);

		if (branch_product_id != NULL)
			break;
	}
	oscap_iterator_free(branches);
	printf("Branch Product ID: %s\n", branch_product_id);
	if (branch_product_id == NULL)
		return;


	struct cvrf_relationship_iterator *relationships = cvrf_product_tree_get_relationships(tree);
	while (cvrf_relationship_iterator_has_more(relationships)) {
		relation = cvrf_relationship_iterator_next(relationships);
		if (!strcmp(branch_product_id, cvrf_relationship_get_relates_to_ref(relation))) {
			full_name = cvrf_relationship_get_product_name(relation);
			relation_product_id = cvrf_product_name_get_product_id(full_name);
			printf("Relation Product ID: %s\n", relation_product_id);
			oscap_stringlist_add_string(eval->product_ids, relation_product_id);
		}
	}
	cvrf_relationship_iterator_free(relationships);
}

void cvrf_export_results(struct oscap_source *import_source, struct oscap_source *export_source, const char *os_name) {
	__attribute__nonnull__(import_source);

	const char *export_file = oscap_source_get_filepath(export_source);
	struct xmlTextWriterPtr *writer = xmlNewTextWriterFilename(export_file, 0);
	if (writer == NULL) {
		oscap_setxmlerr(xmlGetLastError());
		return;
	}

	struct cvrf_model_eval *eval = cvrf_model_eval_new();
	struct cvrf_model *model = cvrf_model_import(import_source);
	cvrf_eval_set_model(eval, model);
	cvrf_model_eval_set_os_name(eval, os_name);
	find_all_cvrf_product_ids_by_OS(eval, model);
	cvrf_model_eval_construct_definition_model(eval);

	xmlTextWriterSetIndent(writer, 1);
	xmlTextWriterSetIndentString(writer, BAD_CAST "  ");
	xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);

	xmlTextWriterStartElementNS(writer, NULL, TAG_CVRF_DOC, CVRF_NS);

	cvrf_export_element(cvrf_model_get_doc_title(model), "DocumentTitle", writer);
	cvrf_export_element(os_name, "OS Name", writer);

	xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "Identification", NULL);
	xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "ID", NULL);
	xmlTextWriterWriteString(writer, BAD_CAST cvrf_model_get_identification(model));
	xmlTextWriterEndElement(writer);
	xmlTextWriterEndElement(writer);

	struct cvrf_vulnerability_iterator *it = cvrf_model_get_vulnerabilities(model);
	bool vulnerable = false;
	while (cvrf_vulnerability_iterator_has_more(it)) {
		struct cvrf_vulnerability *vuln = cvrf_vulnerability_iterator_next(it);
		struct oscap_string_iterator *product_ids = cvrf_model_eval_get_product_ids(eval);

		xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "Vulnerability", VULN_NS);
		xmlTextWriterWriteAttribute(writer, BAD_CAST "Ordinal", BAD_CAST (char *)cvrf_vulnerablity_get_ordinal(vuln));
		cvrf_export_element(cvrf_vulnerability_get_cve_id(vuln), "CVE", writer);

		while (oscap_string_iterator_has_more(product_ids)) {
			const char *product_id = oscap_string_iterator_next(product_ids);

			xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "Result", NULL);
			xmlTextWriterWriteAttribute(writer, ATTR_PRODUCT_ID, BAD_CAST product_id);
			if (cvrf_product_vulnerability_fixed(vuln, product_id)) {
				xmlTextWriterWriteString(writer, BAD_CAST "FIXED");
			}
			else {
				xmlTextWriterWriteString(writer, BAD_CAST "VULNERABLE");
				vulnerable = true;
			}
			xmlTextWriterEndElement(writer);
		}

		if (vulnerable && cvrf_vulnerability_get_remediation_count(vuln) > 0) {
			xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "Remediations", NULL);
			OSCAP_FOREACH(cvrf_remediation, e, cvrf_vulnerability_get_remediations(vuln), cvrf_remediation_export(e, writer);)
			xmlTextWriterEndElement(writer);
		}

		oscap_string_iterator_free(product_ids);
		xmlTextWriterEndElement(writer);
		vulnerable = false;
	}
	cvrf_vulnerability_iterator_free(it);
	xmlTextWriterEndElement(writer);

	xmlTextWriterEndDocument(writer);
	cvrf_model_eval_free(eval);
	oscap_source_free(export_source);
	xmlFreeTextWriter(writer);
	if (xmlGetLastError() != NULL)
		oscap_setxmlerr(xmlGetLastError());
}


static const char *get_rpm_name_from_cvrf_product_id(struct cvrf_model_eval *eval, const char *product_id) {

	const char *rpm_name = NULL;
	struct cvrf_model *model = cvrf_eval_get_model(eval);
	struct cvrf_product_tree *tree = cvrf_model_get_product_tree(model);
	struct cvrf_branch *branch;
	struct cvrf_product_name *full_name;

	struct oscap_iterator *branches = cvrf_product_tree_get_branches(tree);
	while (oscap_iterator_has_more(branches)) {
		branch = oscap_iterator_next(branches);

		if (cvrf_branch_get_branch_type(branch) == CVRF_BRANCH_PRODUCT_VERSION) {
			full_name = cvrf_branch_get_cvrf_product_name(branch);

			if (oscap_str_endswith(product_id, cvrf_product_name_get_product_id(full_name))) {
				rpm_name = cvrf_product_name_get_cpe(full_name);
				break;
			}
		}

	}
	oscap_iterator_free(branches);
	return rpm_name;
}

static struct cvrf_rpm_attributes *parse_rpm_name_into_components(struct cvrf_model_eval *eval, const char *product_id) {

	struct cvrf_rpm_attributes *attributes = cvrf_rpm_attributes_new();
	const char *rpm_name = get_rpm_name_from_cvrf_product_id(eval, product_id);
	attributes->full_package_name = strdup(rpm_name);

	struct oscap_string *rpm_name_suffix = oscap_string_new();
	struct oscap_string *rpm_release = oscap_string_new();
	struct oscap_string *evr_format = oscap_string_new();
	int dashes_size = 1;
	int periods_size = 1;

	char *rpm_name_dup = strdup(rpm_name);
	char **split_by_dashes = oscap_split(rpm_name_dup, "-");
	while (split_by_dashes[dashes_size-1] != NULL)
		dashes_size++;
	for (int index = 0; index < dashes_size-3; index++) {
		oscap_string_append_string(rpm_name_suffix, split_by_dashes[index]);
		if (index < dashes_size-4)
			oscap_string_append_char(rpm_name_suffix, '-');
	}
	attributes->rpm_name = strdup(oscap_string_get_cstr(rpm_name_suffix));
	attributes->rpm_version = strdup(split_by_dashes[dashes_size-3]);

	char **split_by_periods = oscap_split(split_by_dashes[dashes_size-2], ".");
	while (split_by_periods[periods_size-1] != NULL)
		periods_size++;
	for (int index = 0; index < periods_size-3; index++) {
		oscap_string_append_string(rpm_release, split_by_periods[index]);
		if (index < periods_size-4)
			oscap_string_append_char(rpm_release, '.');
	}
	attributes->rpm_release = strdup(oscap_string_get_cstr(rpm_release));
	attributes->rpm_architecture = strdup(split_by_periods[periods_size-3]);

	char *product_id_dup = strdup(product_id);
	char **split_by_colon = oscap_split(product_id_dup, ":");
	char *name_with_epoch = oscap_strdup(split_by_colon[1]);
	int name_length = strlen(attributes->rpm_name);

	if (name_length == strlen(name_with_epoch)) {
		oscap_string_append_char(evr_format, '0');
	} else {
		for (int epoch_index = name_length+1; epoch_index < strlen(name_with_epoch); epoch_index++)
			oscap_string_append_char(evr_format, name_with_epoch[epoch_index]);
	}
	oscap_string_append_char(evr_format, ':');
	oscap_string_append_string(evr_format, attributes->rpm_version);
	oscap_string_append_char(evr_format, '-');
	oscap_string_append_string(evr_format, attributes->rpm_release);

	attributes->evr_format = strdup(oscap_string_get_cstr(evr_format));


	oscap_free(rpm_name_dup);
	oscap_free(product_id_dup);
	oscap_string_free(evr_format);
	oscap_string_free(rpm_name_suffix);
	oscap_string_free(rpm_release);
	return attributes;
}

bool cvrf_product_vulnerability_fixed(struct cvrf_vulnerability *vuln, char *product) {

	struct cvrf_product_status_iterator *it = cvrf_vulnerability_get_cvrf_product_statuses(vuln);
	while (cvrf_product_status_iterator_has_more(it)) {
		struct cvrf_product_status *stat = cvrf_product_status_iterator_next(it);
		struct oscap_string_iterator *product_ids = cvrf_product_status_get_ids(stat);

		while (oscap_string_iterator_has_more(product_ids)) {
			const char *product_id = oscap_string_iterator_next(product_ids);

			if (strcmp(product_id, product)) {
				oscap_string_iterator_free(product_ids);
				cvrf_product_status_iterator_free(it);
				return true;
			}
{'fraction_non_alphanumeric': 0.1117854778194659, 'fraction_numerical': 0.0017656146546016333, 'mean_word_length': 7.772829945143594, 'pattern_counts': {'":': 2, '<': 21, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 77}, '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': '3177936', 'n_tokens_mistral': 10789, 'n_tokens_neox': 9986, 'n_words': 1502}