Files
cantata/libmaia/maiaObject.cpp

294 lines
8.8 KiB
C++

/*
* libMaia - maiaObject.cpp
* Copyright (c) 2003 Frerich Raabe <raabe@kde.org> and
* Ian Reinhart Geiser <geiseri@kde.org>
* Copyright (c) 2007 Sebastian Wiedenroth <wiedi@frubar.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "maiaObject.h"
MaiaObject::MaiaObject(QObject* parent) : QObject(parent){
QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
}
QDomElement MaiaObject::toXml(QVariant arg) {
//dummy document
QDomDocument doc;
//value element, we need this in each case
QDomElement tagValue = doc.createElement("value");
switch(arg.type()) {
case QVariant::String: {
QDomElement tagString = doc.createElement("string");
QDomText textString = doc.createTextNode(arg.toString());
tagValue.appendChild(tagString);
tagString.appendChild(textString);
return tagValue;
} case QVariant::Int: {
QDomElement tagInt = doc.createElement("int");
QDomText textInt = doc.createTextNode(QString::number(arg.toInt()));
tagValue.appendChild(tagInt);
tagInt.appendChild(textInt);
return tagValue;
} case QVariant::Double: {
QDomElement tagDouble = doc.createElement("double");
QDomText textDouble = doc.createTextNode(QString::number(arg.toDouble()));
tagValue.appendChild(tagDouble);
tagDouble.appendChild(textDouble);
return tagValue;
} case QVariant::Bool: {
QString textValue = arg.toBool() ? "1" : "0";
QDomElement tag = doc.createElement("boolean");
QDomText text = doc.createTextNode(textValue);
tagValue.appendChild(tag);
tag.appendChild(text);
return tagValue;
} case QVariant::ByteArray: {
QString textValue = arg.toByteArray().toBase64();
QDomElement tag = doc.createElement("base64");
QDomText text = doc.createTextNode(textValue);
tagValue.appendChild(tag);
tag.appendChild(text);
return tagValue;
} case QVariant::DateTime: {
QString textValue = arg.toDateTime().toString("yyyyMMddThh:mm:ss");
QDomElement tag = doc.createElement("datetime.iso8601");
QDomText text = doc.createTextNode(textValue);
tagValue.appendChild(tag);
tag.appendChild(text);
return tagValue;
} case QVariant::List: {
QDomElement tagArray = doc.createElement("array");
QDomElement tagData = doc.createElement("data");
tagArray.appendChild(tagData);
tagValue.appendChild(tagArray);
const QList<QVariant> args = arg.toList();
for(int i = 0; i < args.size(); ++i) {
tagData.appendChild(toXml(args.at(i)));
}
return tagValue;
} case QVariant::Map: {
QDomElement tagStruct = doc.createElement("struct");
QDomElement member;
QDomElement name;
tagValue.appendChild(tagStruct);
QMap<QString, QVariant> map = arg.toMap();
QMapIterator<QString, QVariant> i(map);
while(i.hasNext()) {
i.next();
member = doc.createElement("member");
name = doc.createElement("name");
// (key) -> name -> member -> struct
tagStruct.appendChild(member);
member.appendChild(name);
name.appendChild(doc.createTextNode(i.key()));
// add variables by recursion
member.appendChild(toXml(i.value()));
}
return tagValue;
} default:
qDebug() << "Failed to marshal unknown variant type: " << arg.type() << endl;
}
return QDomElement(); //QString::null;
}
QVariant MaiaObject::fromXml(const QDomElement &elem) {
if(elem.tagName().toLower() != "value") {
return QVariant();
}
// If no type is indicated, the type is string.
if(!elem.firstChild().isElement()) {
return QVariant(elem.text());
}
const QDomElement typeElement = elem.firstChild().toElement();
const QString typeName = typeElement.tagName().toLower();
if(typeName == "string")
return QVariant(typeElement.text());
else if(typeName == "i4" || typeName == "int")
return QVariant(typeElement.text().toInt());
else if(typeName == "double")
return QVariant(typeElement.text().toDouble());
else if (typeName == "boolean") {
if(typeElement.text().toLower() == "true" || typeElement.text() == "1")
return QVariant(true);
else
return QVariant(false);
} else if(typeName == "base64")
return QVariant(QByteArray::fromBase64( typeElement.text().toLatin1()));
else if(typeName == "datetime" || typeName == "datetime.iso8601")
return QVariant(QDateTime::fromString(typeElement.text(), "yyyyMMddThh:mm:ss"));
else if(typeName == "nil") // Non-standard extension: http://ontosys.com/xml-rpc/extensions.php
return QVariant();
else if ( typeName == "array" ) {
QList<QVariant> values;
QDomNode valueNode = typeElement.firstChild().firstChild();
while(!valueNode.isNull()) {
values << fromXml(valueNode.toElement());
valueNode = valueNode.nextSibling();
}
return QVariant(values);
}
else if ( typeName == "struct" ) {
QMap<QString, QVariant> map;
QDomNode memberNode = typeElement.firstChild();
while(!memberNode.isNull()) {
const QString key = memberNode.toElement().elementsByTagName("name").item(0).toElement().text();
const QVariant data = fromXml(memberNode.toElement().elementsByTagName("value").item(0).toElement());
map[key] = data;
memberNode = memberNode.nextSibling();
}
return QVariant(map);
} else {
qDebug() << "Cannot demarshal unknown type " << typeElement.tagName().toLower();
}
return QVariant();
}
QString MaiaObject::prepareCall(QString method, QList<QVariant> args) {
QDomDocument doc;
QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", QString("version=\"1.0\" encoding=\"UTF-8\"" ));
doc.appendChild(header);
QDomElement methodCall = doc.createElement("methodCall");
QDomElement methodName = doc.createElement("methodName");
QDomElement params = doc.createElement("params");
QDomElement param;
doc.appendChild(methodCall);
methodCall.appendChild(methodName);
methodName.appendChild(doc.createTextNode(method));
methodCall.appendChild(params);
for(int i = 0; i < args.size(); ++i) {
param = doc.createElement("param");
param.appendChild(toXml(args.at(i)));
params.appendChild(param);
}
return doc.toString();
}
QString MaiaObject::prepareResponse(QVariant arg) {
QDomDocument doc;
QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", QString("version=\"1.0\" encoding=\"UTF-8\"" ));
doc.appendChild(header);
QDomElement methodResponse = doc.createElement("methodResponse");
QDomElement params = doc.createElement("params");
QDomElement param;
doc.appendChild(methodResponse);
methodResponse.appendChild(params);
if(!arg.isNull()) {
param = doc.createElement("param");
param.appendChild(toXml(arg));
params.appendChild(param);
}
return doc.toString();
}
void MaiaObject::parseResponse(QString response, QNetworkReply* reply) {
QDomDocument doc;
QVariant arg;
QString errorMsg;
int errorLine;
int errorColumn;
if(!doc.setContent(response, &errorMsg, &errorLine, &errorColumn)) {
emit fault(-32700, QString("parse error: response not well formed at line %1: %2").arg(errorLine).arg(errorMsg), reply);
delete this;
return;
}
if(doc.documentElement().firstChild().toElement().tagName().toLower() == "params") {
QDomNode paramNode = doc.documentElement().firstChild().firstChild();
if(!paramNode.isNull()) {
arg = fromXml( paramNode.firstChild().toElement() );
}
emit aresponse(arg, reply);
} else if(doc.documentElement().firstChild().toElement().tagName().toLower() == "fault") {
const QVariant errorVariant = fromXml(doc.documentElement().firstChild().firstChild().toElement());
emit fault(errorVariant.toMap() [ "faultCode" ].toInt(),
errorVariant.toMap() [ "faultString" ].toString(),
reply);
} else {
emit fault(-32600,
QString("parse error: invalid xml-rpc. not conforming to spec."), // TODO: Is this really worth translating? For Who???
reply);
}
delete this;
return;
}