RetroShare/plugins/FeedReader/util/XMLWrapper.cpp

427 lines
8.3 KiB
C++
Raw Normal View History

/****************************************************************
* RetroShare GUI is distributed under the following license:
*
* Copyright (C) 2012 by Thunder
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include <iostream>
#include <string.h>
#include "XMLWrapper.h"
#include "XPathWrapper.h"
#include <util/rsstring.h>
#include <util/rsthreads.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
static RsMutex xmlMtx("XMLWrapper");
static std::string xmlErrorString;
XMLWrapper::XMLWrapper()
{
mDocument = NULL;
mCharEncodingHandler = xmlFindCharEncodingHandler ("UTF8");
if (!mCharEncodingHandler) {
/* no encoding handler found */
std::cerr << "XMLWrapper::XMLWrapper - no encoding handler found" << std::endl;
}
}
XMLWrapper::~XMLWrapper()
{
cleanup();
xmlCharEncCloseFunc(mCharEncodingHandler);
}
static void xmlErrorHandler(void */*context*/, const char *msg, ...)
{
va_list vl;
va_start(vl, msg);
rs_sprintf_append_args(xmlErrorString, msg, vl);
va_end(vl);
}
void XMLWrapper::handleError(bool init, std::string &errorString)
{
if (init) {
xmlMtx.lock();
xmlErrorString.clear();
errorString.clear();
xsltSetGenericErrorFunc(this, xmlErrorHandler);
xmlSetGenericErrorFunc(this, xmlErrorHandler);
} else {
xsltSetGenericErrorFunc(NULL, NULL);
xmlSetGenericErrorFunc(NULL, NULL);
errorString = xmlErrorString;
xmlErrorString.clear();
xmlMtx.unlock();
}
}
void XMLWrapper::trimString(std::string &string)
{
/* trim left */
std::string::size_type find = string.find_first_not_of(" \t\r\n");
if (find != std::string::npos) {
string.erase(0, find);
/* trim right */
find = string.find_last_not_of(" \t\r\n");
if (find != std::string::npos) {
string.erase(find + 1);
}
} else {
string.clear();
}
}
XMLWrapper &XMLWrapper::operator=(const XMLWrapper &xml)
{
cleanup();
const xmlDocPtr document = xml.getDocument();
if (document) {
mDocument = xmlCopyDoc(document, 1);
}
return *this;
}
void XMLWrapper::cleanup()
{
if (mDocument) {
xmlFreeDoc(mDocument);
mDocument = NULL;
}
}
void XMLWrapper::attach(xmlDocPtr document)
{
cleanup();
mDocument = document;
}
bool XMLWrapper::convertToString(const xmlChar *xmlText, std::string &text)
{
bool result = false;
xmlBufferPtr in = xmlBufferCreateStatic((void*) xmlText, xmlStrlen(xmlText));
xmlBufferPtr out = xmlBufferCreate();
int ret = xmlCharEncOutFunc(mCharEncodingHandler, out, in);
if (ret >= 0) {
result = true;
text = (char*) xmlBufferContent(out);
}
xmlBufferFree(in);
xmlBufferFree(out);
return result;
}
bool XMLWrapper::convertFromString(const char *text, xmlChar *&xmlText)
{
bool result = false;
xmlBufferPtr in = xmlBufferCreateStatic((void*) text, strlen(text));
xmlBufferPtr out = xmlBufferCreate();
int ret = xmlCharEncInFunc(mCharEncodingHandler, out, in);
if (ret >= 0) {
result = true;
#if LIBXML_VERSION >= 20800
xmlText = xmlBufferDetach(out);
#else
xmlText = xmlStrdup(xmlBufferContent(out));
#endif
}
xmlBufferFree(in);
xmlBufferFree(out);
return result;
}
xmlDocPtr XMLWrapper::getDocument() const
{
return mDocument;
}
xmlNodePtr XMLWrapper::getRootElement() const
{
if (mDocument) {
return xmlDocGetRootElement(mDocument);
}
return NULL;
}
bool XMLWrapper::readXML(const char *xml)
{
cleanup();
handleError(true, mLastErrorString);
mDocument = xmlReadDoc(BAD_CAST xml, "", NULL, /*XML_PARSE_NOERROR | XML_PARSE_NOWARNING | */XML_PARSE_COMPACT | XML_PARSE_NOENT | XML_PARSE_NOCDATA);
handleError(false, mLastErrorString);
if (mDocument) {
return true;
}
return false;
}
bool XMLWrapper::getContent(xmlNodePtr node, std::string &content, bool trim)
{
content.clear();
if (!node) {
return false;
}
xmlChar *xmlContent = xmlNodeGetContent(node);
if (!xmlContent) {
return true;
}
bool result = convertToString(xmlContent, content);
xmlFree(xmlContent);
if (result && trim) {
trimString(content);
}
return result;
}
bool XMLWrapper::setContent(xmlNodePtr node, const char *content)
{
if (!node) {
return false;
}
xmlChar *xmlContent;
if (!convertFromString(content, xmlContent)) {
return false;
}
xmlNodeSetContent(node, xmlContent);
xmlFree(xmlContent);
return true;
}
bool XMLWrapper::nodeDump(xmlNodePtr node, std::string &content, bool trim)
{
content.clear();
if (!mDocument) {
return false;
}
if (!node) {
return false;
}
bool result = false;
xmlBufferPtr buffer = xmlBufferCreate();
if (buffer) {
xmlOutputBufferPtr outputBuffer = xmlOutputBufferCreateBuffer(buffer, NULL);
if (outputBuffer) {
xmlNodeDumpOutput(outputBuffer, mDocument, node, 0, 0, "UTF8");
xmlOutputBufferClose(outputBuffer);
outputBuffer = NULL;
result = convertToString(buffer->content, content);
if (result && trim) {
trimString(content);
}
}
xmlBufferFree(buffer);
buffer = NULL;
}
return result;
}
std::string XMLWrapper::nodeName(xmlNodePtr node)
{
std::string name;
if (node) {
convertToString(node->name, name);
}
return name;
}
std::string XMLWrapper::attrName(xmlAttrPtr attr)
{
std::string name;
if (attr) {
convertToString(attr->name, name);
}
return name;
}
xmlNodePtr XMLWrapper::findNode(xmlNodePtr node, const char *name, bool children)
{
if (node->name) {
if (xmlStrEqual(node->name, BAD_CAST name)) {
return node;
}
}
xmlNodePtr nodeFound = NULL;
if (children) {
if (node->children) {
nodeFound = findNode(node->children, name, children);
if (nodeFound) {
return nodeFound;
}
}
}
if (node->next) {
nodeFound = findNode(node->next, name, children);
if (nodeFound) {
return nodeFound;
}
}
return NULL;
}
bool XMLWrapper::getChildText(xmlNodePtr node, const char *childName, std::string &text)
{
if (node == NULL || node->children == NULL) {
return false;
}
xmlNodePtr child = findNode(node->children, childName, true);
if (!child) {
return false;
}
if (child->type != XML_ELEMENT_NODE) {
return false;
}
if (!child->children) {
return false;
}
if (getAttr(child, "type") == "xhtml") {
/* search div */
xmlNodePtr div = findNode(child->children, "div", false);
if (!div) {
return false;
}
return nodeDump(div, text, true);
}
if (child->children->type != XML_TEXT_NODE) {
return false;
}
if (child->children->content) {
return convertToString(child->children->content, text);
}
return true;
}
std::string XMLWrapper::getAttr(xmlNodePtr node, xmlAttrPtr attr)
{
return getAttr(node, (const char*) attr->name);
}
std::string XMLWrapper::getAttr(xmlNodePtr node, const char *name)
{
if (!node || !name) {
return "";
}
std::string value;
xmlChar *xmlValue = xmlGetProp(node, BAD_CAST name);
if (xmlValue) {
convertToString(xmlValue, value);
xmlFree(xmlValue);
}
return value;
}
bool XMLWrapper::setAttr(xmlNodePtr node, const char *name, const char *value)
{
if (!node || !name) {
return false;
}
xmlChar *xmlValue = NULL;
if (!convertFromString(value, xmlValue)) {
return false;
}
xmlAttrPtr xmlAttr = xmlSetProp (node, BAD_CAST name, xmlValue);
xmlFree(xmlValue);
return xmlAttr != NULL;
}
XPathWrapper *XMLWrapper::createXPath()
{
if (mDocument) {
return new XPathWrapper(*this);
}
return NULL;
}
bool XMLWrapper::transform(const XMLWrapper &style, XMLWrapper &result)
{
handleError(true, mLastErrorString);
xmlDocPtr resultDoc = NULL;
xsltStylesheetPtr stylesheet = xsltParseStylesheetDoc(style.getDocument());
if (stylesheet) {
resultDoc = xsltApplyStylesheet(stylesheet, getDocument(), NULL);
stylesheet->doc = NULL; // xsltFreeStylesheet is freeing doc
xsltFreeStylesheet(stylesheet);
}
result.attach(resultDoc);
handleError(false, mLastErrorString);
return resultDoc ? true : false;
}