/*
* Copyright 2009 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:
* Lukas Kuklinek <lkuklinek@redhat.com>
*/
/*
* text.c
*
* Created on: Jan 14, 2010
* Author: david.niemoller
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdio.h>
#include "text_priv.h"
#include "util.h"
#include "list.h"
#include "oscap_helpers.h"
const char * const OSCAP_LANG_ENGLISH = "en";
const char * const OSCAP_LANG_ENGLISH_US = "en-US";
const char * const OSCAP_LANG_DEFAULT = "en-US";
const struct oscap_text_traits OSCAP_TEXT_TRAITS_PLAIN = { .html = false };
const struct oscap_text_traits OSCAP_TEXT_TRAITS_HTML = { .html = true };
OSCAP_ACCESSOR_STRING(oscap_text, text)
OSCAP_ACCESSOR_STRING(oscap_text, lang)
OSCAP_GENERIC_GETTER(bool, oscap_text, is_html, traits.html)
OSCAP_GENERIC_GETTER(bool, oscap_text, can_substitute, traits.can_substitute)
OSCAP_GENERIC_GETTER(bool, oscap_text, can_override, traits.can_override)
OSCAP_GENERIC_GETTER(bool, oscap_text, overrides, traits.overrides)
OSCAP_ITERATOR_GEN_T(struct oscap_text *, oscap_text)
/*OSCAP_ITERATOR_RESET(oscap_text)*/
OSCAP_ITERATOR_REMOVE_T(struct oscap_text *, oscap_text, oscap_text_free)
bool oscap_text_set_overrides(struct oscap_text *text, bool overrides)
{
text->traits.overrides = overrides;
return text->traits.can_override;
}
void oscap_text_free(struct oscap_text *text)
{
if (text != NULL) {
free(text->lang);
free(text->text);
free(text);
}
}
struct oscap_text *oscap_text_new_full(struct oscap_text_traits traits, const char *string, const char *lang)
{
struct oscap_text *text = calloc(1, sizeof(struct oscap_text));
text->traits = traits;
text->text = oscap_strdup(string);
text->lang = oscap_strdup(lang);
return text;
}
struct oscap_text *oscap_text_new(void)
{
return oscap_text_new_full(OSCAP_TEXT_TRAITS_PLAIN, NULL, NULL);
}
struct oscap_text * oscap_text_clone(const struct oscap_text * text)
{
return oscap_text_new_full(text->traits, text->text, text->lang);
}
struct oscap_text *oscap_text_new_html(void)
{
//assert(false); // TODO implement
return oscap_text_new_full(OSCAP_TEXT_TRAITS_HTML, NULL, NULL);
}
struct oscap_text *oscap_text_new_parse(struct oscap_text_traits traits, xmlTextReaderPtr reader)
{
assert(reader != NULL);
// new text
struct oscap_text *text = oscap_text_new_full(traits, NULL, NULL);
// extract 'override' attribute
if (text->traits.can_override) {
xmlTextReaderMoveToAttribute(reader, BAD_CAST "override");
text->traits.overrides = oscap_string_to_enum(OSCAP_BOOL_MAP, (const char *) xmlTextReaderConstValue(reader));
if (xmlTextReaderConstValue(reader) != NULL) text->traits.override_given = true;
}
// extract language
text->lang = (char *) xmlTextReaderXmlLang(reader);
xmlTextReaderMoveToElement(reader);
// extract content
if (text->traits.html || text->traits.can_substitute)
text->text = oscap_get_xml(reader);
else text->text = oscap_element_string_copy(reader);
return text;
}
xmlNode *oscap_text_to_dom(struct oscap_text *text, xmlNode *parent, const char *elname)
{
if (!text) return NULL;
xmlNode *text_node = NULL;
if (text->traits.html || text->traits.can_substitute) {
text_node = oscap_xmlstr_to_dom(parent, elname, text->text);
// make sure we use parent's namespace
xmlSetNs(text_node, parent->ns);
}
else {
// NULL as ns here means that namespace is inherited from parent
text_node = xmlNewTextChild(parent, NULL, BAD_CAST elname, BAD_CAST text->text);
}
if (text_node == NULL) return NULL;
if (text->lang)
xmlNodeSetLang(text_node, BAD_CAST text->lang);
if (text->traits.can_override && text->traits.overrides)
xmlNewProp(text_node, BAD_CAST "override", BAD_CAST "true");
return text_node;
}
bool oscap_text_export(struct oscap_text *text, xmlTextWriter *writer, const char *elname)
{
if (text == NULL || writer == NULL) return false;
if (elname) xmlTextWriterStartElement(writer, BAD_CAST elname);
if (text->lang)
xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang", BAD_CAST text->lang);
if (text->traits.can_override && text->traits.overrides)
xmlTextWriterWriteAttribute(writer, BAD_CAST "override", BAD_CAST "true");
if (text->traits.html || text->traits.can_substitute)
xmlTextWriterWriteRaw(writer, BAD_CAST text->text);
else xmlTextWriterWriteString(writer, BAD_CAST text->text);
if (elname) xmlTextWriterEndElement(writer);
return true;
}
char *_xhtml_to_plaintext(const char *xhtml_in)
{
char *out = NULL;
char *str = oscap_sprintf("<x xmlns='http://www.w3.org/1999/xhtml'>%s</x>", xhtml_in);
xmlDoc *doc = xmlParseMemory(str, strlen(str));
if (doc == NULL) {
free(str);
return NULL;
}
xmlNode *root = xmlDocGetRootElement(doc);
if (root == NULL) {
free(str);
return out;
}
// TODO: better HTML -> plaintext conversion
// (perhaps use xml_iterate)
out = (char*) xmlNodeGetContent(root);
xmlFreeDoc(doc);
free(str);
return out;
}
char *oscap_text_get_plaintext(const struct oscap_text *text)
{
if (text == NULL) return NULL;
if (!text->traits.html) return oscap_strdup(text->text);
return _xhtml_to_plaintext(text->text);
}
bool oscap_textlist_export(struct oscap_text_iterator *texts, xmlTextWriter *writer, const char *elname)
{
if (texts == NULL || writer == NULL || elname == NULL) return false;
OSCAP_FOR(oscap_text, text, texts)
oscap_text_export(text, writer, elname);
return true;
}
struct oscap_text *oscap_textlist_get_preferred_text(struct oscap_text_iterator *texts, const char *preferred_lang)
{
if (preferred_lang == NULL)
preferred_lang = OSCAP_LANG_DEFAULT;
oscap_text_iterator_reset(texts);
while (oscap_text_iterator_has_more(texts)) {
struct oscap_text *text = oscap_text_iterator_next(texts);
const char *lang = oscap_text_get_lang(text);
if (lang && strcmp(lang, preferred_lang) == 0)
return text;
}
// not found as exact match in preferred language, try to find implicit match
oscap_text_iterator_reset(texts);
while (oscap_text_iterator_has_more(texts)) {
struct oscap_text *text = oscap_text_iterator_next(texts);
const char *lang = oscap_text_get_lang(text);
if (lang == NULL)
return text;
}
// fallback to any language
oscap_text_iterator_reset(texts);
while (oscap_text_iterator_has_more(texts)) {
struct oscap_text *text = oscap_text_iterator_next(texts);
return text;
}
// nothing found
return NULL;
}
char *oscap_textlist_get_preferred_plaintext(struct oscap_text_iterator *texts, const char *preferred_lang)
{
struct oscap_text *text = oscap_textlist_get_preferred_text(texts, preferred_lang);
return (text != NULL) ? oscap_text_get_plaintext(text) : NULL;
}