mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-11 17:04:31 -05:00
ef49000b9a
- Added error handling to xml functions - Added xslt transformation - Added retransform of existing messages - Redesigned preview dialog - Enabled embed images for forum feeds - Changed config format, switching back to an older version results in a loss of all data of the FeedReader Added new base class RSPlainTextEdit with placeholder text. New library libxslt needed git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6081 b45a01b8-16f6-495d-af2f-9b41ad6348cc
427 lines
8.3 KiB
C++
427 lines
8.3 KiB
C++
/****************************************************************
|
|
* 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;
|
|
}
|