/*
* Copyright 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
* Šimon Lukašík
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>
#include "public/cpe_name.h"
#include "cpe_ctx_priv.h"
#include "cpedict_ext_priv.h"
#include "common/_error.h"
#include "common/list.h"
#include "common/util.h"
#include "common/xmlns_priv.h"
#include "common/xmltext_priv.h"
#define ATTR_NAME_STR "name"
#define ATTR_DATE_STR "date"
#define ATTR_TYPE_STR "type"
#define TAG_CPE_EXT_DEPRECATION_STR "deprecation"
#define TAG_CPE_EXT_DEPRECATEDBY_STR "deprecated-by"
enum cpe_deprecation_type { ///< cpe_dict_ext:deprecationTypeType
CPE_DEP_NAME_CORRECTION = 1,
CPE_DEP_NAME_REMOVAL = 2,
CPE_DEP_ADDITIONAL_INFORMATION = 3,
};
struct cpe_ext_deprecatedby { ///< <cpe_dict_ext:deprecated-by> node
char *name; ///< @name attribute
enum cpe_deprecation_type type; ///< @type attribute
};
struct cpe_ext_deprecation { ///< <cpe_dict_ext:deprecation> node
char *date; ///< @date attribute
struct oscap_list *deprecatedbys; ///< <deprecated-by> sub-nodes
};
struct cpe23_item { ///< <cpe23-item> node
char *name; ///< @name attribute
struct oscap_list *deprecations; ///< <deprecation> sub-nodes
};
static const struct oscap_string_map CPE_EXT_DEPRECATION_MAP[] = {
{CPE_DEP_NAME_CORRECTION, "NAME_CORRECTION"},
{CPE_DEP_NAME_REMOVAL, "NAME_REMOVAL"},
{CPE_DEP_ADDITIONAL_INFORMATION, "ADDITIONAL_INFORMATION"},
{0, NULL}
};
struct cpe_ext_deprecatedby_iterator;
static bool cpe_ext_deprecatedby_iterator_has_more(struct cpe_ext_deprecatedby_iterator *it);
static struct cpe_ext_deprecatedby *cpe_ext_deprecatedby_iterator_next(struct cpe_ext_deprecatedby_iterator *it);
static void cpe_ext_deprecatedby_iterator_free(struct cpe_ext_deprecatedby_iterator *it);
void cpe_ext_deprecatedby_iterator_reset(struct cpe_ext_deprecatedby_iterator *it);
static void cpe_ext_deprecatedby_free(struct cpe_ext_deprecatedby *deprecatedby);
struct cpe_ext_deprecatedby_iterator *cpe_ext_deprecation_get_deprecatedbys(const struct cpe_ext_deprecation *deprecation);
bool cpe_ext_deprecation_add_deprecatedby(struct cpe_ext_deprecation *deprecation, struct cpe_ext_deprecatedby *deprecatedby);
struct cpe_ext_deprecation_iterator;
static bool cpe_ext_deprecation_iterator_has_more(struct cpe_ext_deprecation_iterator *it);
static struct cpe_ext_deprecation *cpe_ext_deprecation_iterator_next(struct cpe_ext_deprecation_iterator *it);
static void cpe_ext_deprecation_iterator_free(struct cpe_ext_deprecation_iterator *it);
void cpe_ext_deprecation_iterator_reset(struct cpe_ext_deprecation_iterator *it);
static void cpe_ext_deprecation_free(struct cpe_ext_deprecation *deprecation);
struct cpe_ext_deprecation_iterator *cpe23_item_get_deprecations(const struct cpe23_item *item);
bool cpe23_item_add_deprecation(struct cpe23_item *item, struct cpe_ext_deprecation *deprecation);
static struct cpe_ext_deprecatedby *cpe_ext_deprecatedby_new()
{
return calloc(1, sizeof(struct cpe_ext_deprecatedby));
}
static struct cpe_ext_deprecation *cpe_ext_deprecation_new()
{
struct cpe_ext_deprecation *deprecation = calloc(1, sizeof(struct cpe_ext_deprecation));
deprecation->deprecatedbys = oscap_list_new();
return deprecation;
}
static struct cpe23_item *cpe23_item_new()
{
struct cpe23_item *item = calloc(1, sizeof(struct cpe23_item));
item->deprecations = oscap_list_new();
return item;
}
static struct cpe_ext_deprecatedby *cpe_ext_deprecatedby_parse(xmlTextReaderPtr reader)
{
__attribute__nonnull__(reader);
if (xmlStrcmp(xmlTextReaderConstLocalName(reader), BAD_CAST TAG_CPE_EXT_DEPRECATEDBY_STR) != 0 ||
xmlTextReaderNodeType(reader) != 1) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Found '%s' node when expecting: '%s'!",
xmlTextReaderConstLocalName(reader), TAG_CPE_EXT_DEPRECATEDBY_STR);
}
const xmlChar* nsuri = xmlTextReaderConstNamespaceUri(reader);
if (nsuri && xmlStrcmp(nsuri, BAD_CAST XMLNS_CPE2D3_EXTENSION) != 0) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Found '%s' namespace when expecting: '%s'!",
nsuri, XMLNS_CPE2D3_EXTENSION);
return NULL;
}
struct cpe_ext_deprecatedby *deprecatedby = cpe_ext_deprecatedby_new();
deprecatedby->name = (char *) xmlTextReaderGetAttribute(reader, BAD_CAST ATTR_NAME_STR);
char *type = (char *) xmlTextReaderGetAttribute(reader, BAD_CAST ATTR_TYPE_STR);
if (type == NULL) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Compulsory attribute '%s' missing at '%s' element.",
ATTR_TYPE_STR, TAG_CPE_EXT_DEPRECATEDBY_STR);
cpe_ext_deprecatedby_free(deprecatedby);
return NULL;
}
deprecatedby->type = oscap_string_to_enum(CPE_EXT_DEPRECATION_MAP, type);
free(type);
return deprecatedby;
}
static int cpe_ext_deprecatedby_export(const struct cpe_ext_deprecatedby *deprecatedby, xmlTextWriterPtr writer)
{
__attribute__nonnull__(writer);
__attribute__nonnull__(deprecatedby);
xmlTextWriterStartElementNS(writer, NULL, BAD_CAST TAG_CPE_EXT_DEPRECATEDBY_STR,
BAD_CAST XMLNS_CPE2D3_EXTENSION);
if (deprecatedby->name != NULL) {
xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_NAME_STR, BAD_CAST deprecatedby->name);
}
if (deprecatedby->type != 0) {
xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_TYPE_STR,
BAD_CAST oscap_enum_to_string(CPE_EXT_DEPRECATION_MAP, deprecatedby->type));
}
xmlTextWriterEndElement(writer);
if (xmlGetLastError() != NULL)
oscap_setxmlerr(xmlGetLastError());
return 0;
}
static struct cpe_ext_deprecation *cpe_ext_deprecation_parse(xmlTextReaderPtr reader)
{
__attribute__nonnull__(reader);
if (xmlStrcmp(xmlTextReaderConstLocalName(reader), BAD_CAST TAG_CPE_EXT_DEPRECATION_STR) != 0 ||
xmlTextReaderNodeType(reader) != 1) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Found '%s' node when expecting: '%s'!",
xmlTextReaderConstLocalName(reader), TAG_CPE_EXT_DEPRECATION_STR);
}
const xmlChar* nsuri = xmlTextReaderConstNamespaceUri(reader);
if (nsuri && xmlStrcmp(nsuri, BAD_CAST XMLNS_CPE2D3_EXTENSION) != 0) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Found '%s' namespace when expecting: '%s'!",
nsuri, XMLNS_CPE2D3_EXTENSION);
return NULL;
}
struct cpe_ext_deprecation *deprecation = cpe_ext_deprecation_new();
deprecation->date = (char *) xmlTextReaderGetAttribute(reader, BAD_CAST ATTR_DATE_STR);
if (xmlTextReaderIsEmptyElement(reader) == 0) { // the element contains child nodes
xmlTextReaderNextNode(reader);
while (xmlStrcmp(xmlTextReaderConstLocalName(reader), BAD_CAST TAG_CPE_EXT_DEPRECATION_STR) != 0) {
if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_ELEMENT) {
xmlTextReaderNextNode(reader);
continue;
}
if (xmlStrcmp(xmlTextReaderConstLocalName(reader), BAD_CAST TAG_CPE_EXT_DEPRECATEDBY_STR) == 0) {
struct cpe_ext_deprecatedby *deprecatedby = cpe_ext_deprecatedby_parse(reader);
if (deprecatedby == NULL) {
cpe_ext_deprecation_free(deprecation);
return NULL;
}
oscap_list_add(deprecation->deprecatedbys, deprecatedby);
}
else {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Unexpected element within deprecation element: '%s'",
xmlTextReaderConstLocalName(reader));
cpe_ext_deprecation_free(deprecation);
return NULL;
}
xmlTextReaderNextNode(reader);
}
}
return deprecation;
}
static int cpe_ext_deprecation_export(const struct cpe_ext_deprecation *deprecation, xmlTextWriterPtr writer)
{
__attribute__nonnull__(writer);
__attribute__nonnull__(deprecation);
xmlTextWriterStartElementNS(writer, NULL, BAD_CAST TAG_CPE_EXT_DEPRECATION_STR,
BAD_CAST XMLNS_CPE2D3_EXTENSION);
if (deprecation->date != NULL) {
xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_DATE_STR, BAD_CAST deprecation->date);
}
OSCAP_FOREACH(cpe_ext_deprecatedby, d, oscap_iterator_new(deprecation->deprecatedbys),
cpe_ext_deprecatedby_export(d, writer););
xmlTextWriterEndElement(writer);
if (xmlGetLastError() != NULL)
oscap_setxmlerr(xmlGetLastError());
return 0;
}
struct cpe23_item *cpe23_item_parse(xmlTextReaderPtr reader)
{
__attribute__nonnull__(reader);
if (xmlStrcmp(xmlTextReaderConstLocalName(reader), BAD_CAST TAG_CPE23_ITEM_STR) != 0 ||
xmlTextReaderNodeType(reader) != 1) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Found '%s' node when expecting: '%s'!",
xmlTextReaderConstLocalName(reader), TAG_CPE23_ITEM_STR);
return NULL;
}
const xmlChar* nsuri = xmlTextReaderConstNamespaceUri(reader);
if (nsuri && xmlStrcmp(nsuri, BAD_CAST XMLNS_CPE2D3_EXTENSION) != 0) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Found '%s' namespace when expecting: '%s'!",
nsuri, XMLNS_CPE2D3_EXTENSION);
return NULL;
}
struct cpe23_item *item = cpe23_item_new();
item->name = (char *) xmlTextReaderGetAttribute(reader, BAD_CAST ATTR_NAME_STR);
if (xmlTextReaderIsEmptyElement(reader) == 0) { // the element contains child nodes
xmlTextReaderNextNode(reader);
while (xmlStrcmp(xmlTextReaderConstLocalName(reader), BAD_CAST TAG_CPE23_ITEM_STR) != 0) {
if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_ELEMENT) {
xmlTextReaderNextNode(reader);
continue;
}
if (xmlStrcmp(xmlTextReaderConstLocalName(reader), BAD_CAST TAG_CPE_EXT_DEPRECATION_STR) == 0) {
struct cpe_ext_deprecation *deprecation = cpe_ext_deprecation_parse(reader);
if (deprecation == NULL) {
cpe23_item_free(item);
return NULL;
}
oscap_list_add(item->deprecations, deprecation);
}
else {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Unexpected element within cpe23-item[@name='%s']: '%s'",
item->name, xmlTextReaderConstLocalName(reader));
cpe23_item_free(item);
return NULL;
}
xmlTextReaderNextNode(reader);
}
}
return item;
}
int cpe23_item_export(const struct cpe23_item *item, xmlTextWriterPtr writer)
{
__attribute__nonnull__(writer);
__attribute__nonnull__(item);
xmlTextWriterStartElementNS(writer, NULL, BAD_CAST TAG_CPE23_ITEM_STR,
BAD_CAST XMLNS_CPE2D3_EXTENSION);
if (item->name != NULL) {
xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_NAME_STR, BAD_CAST item->name);
}
OSCAP_FOREACH(cpe_ext_deprecation, d, oscap_iterator_new(item->deprecations),
cpe_ext_deprecation_export(d, writer););
xmlTextWriterEndElement(writer);
if (xmlGetLastError() != NULL)
oscap_setxmlerr(xmlGetLastError());
return 0;
}
static void cpe_ext_deprecatedby_free(struct cpe_ext_deprecatedby *deprecatedby)
{
free(deprecatedby->name);
free(deprecatedby);
}
static void cpe_ext_deprecation_free(struct cpe_ext_deprecation *deprecation)
{
if (deprecation != NULL) {
free(deprecation->date);
oscap_list_free(deprecation->deprecatedbys, (oscap_destruct_func) cpe_ext_deprecatedby_free);
free(deprecation);
}
}
void cpe23_item_free(struct cpe23_item *item)
{
if (item != NULL) {
oscap_list_free(item->deprecations, (oscap_destruct_func) cpe_ext_deprecation_free);
free(item->name);
free(item);
}
}
OSCAP_IGETINS_GEN(cpe_ext_deprecatedby, cpe_ext_deprecation, deprecatedbys, deprecatedby);
OSCAP_IGETINS_GEN(cpe_ext_deprecation, cpe23_item, deprecations, deprecation);