#include #include #include #include #include #include #include "xmlrpcconv.h" #define XMLRPC_WITHSPACES // QVariant to xml conversions // use QByteArray & reference, becouse it is faster, then return QByteArray static void toXmlRpcValue( const int spaces, const QVariant & child, QByteArray & b ); static void toXmlRpcStruct( const int spaces, const QVariantMap & child, QByteArray & b ); static void toXmlRpcArray( const int spaces, const QVariantList & child, QByteArray & b ); // xml to QVariant conversions static QVariant parseXmlRpcValue( const QDomElement & e, QString& err ); static QVariant parseXmlRpcStruct( const QDomElement & e, QString& err ); static QVariant parseXmlRpcArray( const QDomElement & e, QString& err ); QVariant fromXmlRpcResponse( const QString d, QString &err ) { QVariant res = QVariant::Invalid; QDomDocument doc; if ( doc.setContent( d, &err ) ) { QDomElement methodResponse = doc.firstChildElement("methodResponse"); if ( methodResponse.isNull() ) err = "Element 'methodResponse' is absent in response"; else { QDomElement result = methodResponse.firstChildElement(); if ( result.isNull() ) { err = "Element 'params' is absent in response"; return QVariant::Invalid; } else if ( result.tagName() == "params" ) { QDomElement param = result.firstChild().firstChild().toElement(); res = parseXmlRpcValue( param, err ); } else { err = result.text(); } } } return res; } QByteArray toXmlRpcRequest( const QString m, const QList& l ) { #ifdef XMLRPC_WITHSPACES QByteArray r( "\n" ); #else QByteArray r( "" ); #endif #ifdef XMLRPC_WITHSPACES r.append( "\n " ); r.append( m ); r.append( "" ); #else r.append( "" ); r.append( m ); r.append( "" ); #endif #ifdef XMLRPC_WITHSPACES r.append( "\n " ); #else r.append( "" ); #endif for ( int i = 0; i < l.size(); i++ ) { #ifdef XMLRPC_WITHSPACES r.append( "\n " ); #else r.append( "" ); #endif toXmlRpcValue( 6, l.at(i), r ); #ifdef XMLRPC_WITHSPACES r.append( "\n " ); #else r.append( "" ); #endif } #ifdef XMLRPC_WITHSPACES r.append( "\n " ); #else r.append( "" ); #endif #ifdef XMLRPC_WITHSPACES r.append( "\n" ); #else r.append( "" ); #endif return r; } static void toXmlRpcArray( const int spaces, const QVariantList & child, QByteArray & b ) { #ifdef DEBUG_XMLRPC qDebug() << "toXmlRpcArray()"; #endif QListIterator< QVariant > i(child); while( i.hasNext() ) toXmlRpcValue( spaces + 2, i.next(), b ); } static void toXmlRpcStruct( const int spaces, const QVariantMap & child, QByteArray & b ) { #ifdef DEBUG_XMLRPC qDebug() << "toXmlRpcStruct()"; #endif QMapIterator< QString, QVariant > i(child); while( i.hasNext() ) { i.next(); #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" ); #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces + 2, ' ') ); #endif b.append( "" + i.key() + "" ); toXmlRpcValue( spaces + 2, i.value(), b ); #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" ); } } static void toXmlRpcValue( const int spaces, const QVariant & child, QByteArray & b ) { #ifdef DEBUG_XMLRPC qDebug() << "toXmlRpcValue()"; #endif switch( child.type() ) { case QVariant::Int: #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" + QString::number(child.toInt()) + "" ); break; case QVariant::Bool: #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( QString("") + (child.toBool() ? "1" : "0") + "" ); break; case QVariant::String: #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" + child.toString() + "" ); break; case QVariant::Double: #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" + QString::number(child.toDouble()) + "" ); break; case QVariant::DateTime: #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" + child.toDateTime().toString("yyyyMMddTHH:mm:ss") + "" ); break; case QVariant::ByteArray: #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" + child.toByteArray().toBase64() + "" ); break; case QVariant::List: #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" ); toXmlRpcArray( spaces + 2, child.toList(), b ); #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" ); break; case QVariant::Map: #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" ); toXmlRpcStruct( spaces + 2, child.toMap(), b ); #ifdef XMLRPC_WITHSPACES b.append( '\n' ); b.append( QByteArray(spaces, ' ') ); #endif b.append( "" ); break; default: qCritical() << "toXmlRpcValue(): unknown return xmlrpc type" << child.typeName() << endl << child; qFatal("programming error"); } } static QVariant parseXmlRpcValue( const QDomElement & e, QString& err ) { #ifdef DEBUG_XMLRPC qDebug() << "parseXmlRpcValue():" << e.tagName(); #endif QVariant v = QVariant::Invalid; QString tagName = e.tagName(); if( tagName != "value" ) { err = "first param tag is not value"; return v; } QDomElement t = e.firstChild().toElement(); QString type = t.tagName(); if( type == "int" || type == "i4" ) { bool ok; v = t.firstChild().toText().data().toInt( &ok ); if( !ok ) err = "Can't convert int text '" + t.firstChild().toText().data() + "' to number"; } else if( type == "boolean" ) v = t.firstChild().toText().data() == "1" ? true : false; else if( type == "string" ) v = t.firstChild().toText().data(); else if( type == "double" ) { bool ok; v = t.firstChild().toText().data().toDouble( &ok ); if( !ok ) err = "Can't convert int text '" + t.firstChild().toText().data() + "' to number"; } else if( type == "dateTime.iso8601" ) v = QDateTime::fromString( t.firstChild().toText().data(), "yyyyMMddTHH:mm:ss" ); else if( type == "base64" ) v = QByteArray::fromBase64( t.firstChild().toText().data().toLatin1() ); else if ( type == "array" ) v = parseXmlRpcArray( t.firstChild().toElement(), err ); else if ( type == "struct" ) v = parseXmlRpcStruct( t.firstChild().toElement() , err ); else if ( type.length() == 0 ) v = e.toElement().firstChild().toText().data(); else err = "unknown type: '" + type + "'"; return v; } static QVariant parseXmlRpcStruct( const QDomElement &e, QString &err ) { #ifdef DEBUG_XMLRPC qDebug() << "parseXmlRpcStruct():" << e.tagName(); #endif QVariantMap r; QDomElement t = e; while( !t.isNull() ) { if( t.tagName() != "member" ) { err = "no member tag in struct, tag " + e.tagName(); return r; } QDomElement s = t.firstChild().toElement(); if( s.tagName() != "name" ) { err = "no name tag in member struct, tag " + s.tagName(); return r; } // set map value r[ s.firstChild().toText().data() ] = parseXmlRpcValue( s.nextSibling().toElement(), err ); if( !err.isEmpty() ) return r; t = t.nextSibling().toElement(); } return r; } static QVariant parseXmlRpcArray( const QDomElement &e, QString &err ) { #ifdef DEBUG_XMLRPC qDebug() << "parseXmlRpcArray():" << e.tagName(); #endif QVariantList r; if( e.tagName() != "data" ) { err = "no data tag in array, tag " + e.tagName(); return r; } QDomElement t = e.firstChild().toElement(); while( !t.isNull() ) { r.append( parseXmlRpcValue(t,err) ); if( !err.isEmpty() ) return r; t = t.nextSibling().toElement(); } return r; }