mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
426 lines
8.9 KiB
C++
426 lines
8.9 KiB
C++
/*******************************************************************************
|
|
* plugins/FeedReader/util/XMLWrapper.cpp *
|
|
* *
|
|
* Copyright (C) 2012 by Thunder <retroshare.project@gmail.com> *
|
|
* *
|
|
* This program is free software: you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Affero General Public License as *
|
|
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Affero General Public License *
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
|
* *
|
|
*******************************************************************************/
|
|
|
|
#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_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;
|
|
}
|