src/dbus/qdbusutil.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dbus/qdbusutil.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,468 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusutil_p.h"
+
+#include <qdbus_symbols_p.h>
+
+#include <QtCore/qstringlist.h>
+
+#include "qdbusargument.h"
+
+QT_BEGIN_NAMESPACE
+
+static inline bool isValidCharacterNoDash(const QChar &c)
+{
+    register ushort u = c.unicode();
+    return (u >= 'a' && u <= 'z')
+            || (u >= 'A' && u <= 'Z')
+            || (u >= '0' && u <= '9')
+            || (u == '_');
+}
+
+static inline bool isValidCharacter(const QChar &c)
+{
+    register ushort u = c.unicode();
+    return (u >= 'a' && u <= 'z')
+            || (u >= 'A' && u <= 'Z')
+            || (u >= '0' && u <= '9')
+            || (u == '_') || (u == '-');
+}
+
+static inline bool isValidNumber(const QChar &c)
+{
+    register ushort u = c.unicode();
+    return (u >= '0' && u <= '9');
+}
+
+static bool argToString(const QDBusArgument &arg, QString &out);
+
+static bool variantToString(const QVariant &arg, QString &out)
+{
+    int argType = arg.userType();
+
+    if (argType == QVariant::StringList) {
+        out += QLatin1Char('{');
+        QStringList list = arg.toStringList();
+        foreach (QString item, list)
+            out += QLatin1Char('\"') + item + QLatin1String("\", ");
+        if (!list.isEmpty())
+            out.chop(2);
+        out += QLatin1Char('}');
+    } else if (argType == QVariant::ByteArray) {
+        out += QLatin1Char('{');
+        QByteArray list = arg.toByteArray();
+        for (int i = 0; i < list.count(); ++i) {
+            out += QString::number(list.at(i));
+            out += QLatin1String(", ");
+        }
+        if (!list.isEmpty())
+            out.chop(2);
+        out += QLatin1Char('}');
+    } else if (argType == QVariant::List) {
+        out += QLatin1Char('{');
+        QList<QVariant> list = arg.toList();
+        foreach (QVariant item, list) {
+            if (!variantToString(item, out))
+                return false;
+            out += QLatin1String(", ");
+        }
+        if (!list.isEmpty())
+            out.chop(2);
+        out += QLatin1Char('}');
+    } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
+               || argType == QMetaType::Long || argType == QMetaType::LongLong) {
+        out += QString::number(arg.toLongLong());
+    } else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
+               || argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
+        out += QString::number(arg.toULongLong());
+    } else if (argType == QMetaType::Double) {
+        out += QString::number(arg.toDouble());
+    } else if (argType == QMetaType::Bool) {
+        out += QLatin1String(arg.toBool() ? "true" : "false");
+    } else if (argType == qMetaTypeId<QDBusArgument>()) {
+        argToString(qvariant_cast<QDBusArgument>(arg), out);
+    } else if (argType == qMetaTypeId<QDBusObjectPath>()) {
+        const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
+        out += QLatin1String("[ObjectPath: ");
+        out += path;
+        out += QLatin1Char(']');
+    } else if (argType == qMetaTypeId<QDBusSignature>()) {
+        out += QLatin1String("[Signature: ") + qvariant_cast<QDBusSignature>(arg).signature();
+        out += QLatin1Char(']');
+    } else if (argType == qMetaTypeId<QDBusVariant>()) {
+        const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
+        out += QLatin1String("[Variant");
+        int vUserType = v.userType();
+        if (vUserType != qMetaTypeId<QDBusVariant>()
+                && vUserType != qMetaTypeId<QDBusSignature>()
+                && vUserType != qMetaTypeId<QDBusObjectPath>()
+                && vUserType != qMetaTypeId<QDBusArgument>())
+            out += QLatin1Char('(') + QLatin1String(v.typeName()) + QLatin1Char(')');
+        out += QLatin1String(": ");
+        if (!variantToString(v, out))
+            return false;
+        out += QLatin1Char(']');
+    } else if (arg.canConvert(QVariant::String)) {
+        out += QLatin1Char('\"') + arg.toString() + QLatin1Char('\"');
+    } else {
+        out += QLatin1Char('[');
+        out += QLatin1String(arg.typeName());
+        out += QLatin1Char(']');
+    }
+
+    return true;
+}
+
+bool argToString(const QDBusArgument &busArg, QString &out)
+{
+    QString busSig = busArg.currentSignature();
+    bool doIterate = false;
+    QDBusArgument::ElementType elementType = busArg.currentType();
+
+    if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
+            && elementType != QDBusArgument::MapEntryType)
+        out += QLatin1String("[Argument: ") + busSig + QLatin1Char(' ');
+
+    switch (elementType) {
+        case QDBusArgument::BasicType:
+        case QDBusArgument::VariantType:
+            if (!variantToString(busArg.asVariant(), out))
+                return false;
+            break;
+        case QDBusArgument::StructureType:
+            busArg.beginStructure();
+            doIterate = true;
+            break;
+        case QDBusArgument::ArrayType:
+            busArg.beginArray();
+            out += QLatin1Char('{');
+            doIterate = true;
+            break;
+        case QDBusArgument::MapType:
+            busArg.beginMap();
+            out += QLatin1Char('{');
+            doIterate = true;
+            break;
+        case QDBusArgument::MapEntryType:
+            busArg.beginMapEntry();
+            if (!variantToString(busArg.asVariant(), out))
+                return false;
+            out += QLatin1String(" = ");
+            if (!argToString(busArg, out))
+                return false;
+            busArg.endMapEntry();
+            break;
+        case QDBusArgument::UnknownType:
+        default:
+            out += QLatin1String("<ERROR - Unknown Type>");
+            return false;
+    }
+    if (doIterate && !busArg.atEnd()) {
+        while (!busArg.atEnd()) {
+            if (!argToString(busArg, out))
+                return false;
+            out += QLatin1String(", ");
+        }
+        out.chop(2);
+    }
+    switch (elementType) {
+        case QDBusArgument::BasicType:
+        case QDBusArgument::VariantType:
+        case QDBusArgument::UnknownType:
+        case QDBusArgument::MapEntryType:
+            // nothing to do
+            break;
+        case QDBusArgument::StructureType:
+            busArg.endStructure();
+            break;
+        case QDBusArgument::ArrayType:
+            out += QLatin1Char('}');
+            busArg.endArray();
+            break;
+        case QDBusArgument::MapType:
+            out += QLatin1Char('}');
+            busArg.endMap();
+            break;
+    }
+
+    if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
+            && elementType != QDBusArgument::MapEntryType)
+        out += QLatin1Char(']');
+
+    return true;
+}
+
+/*!
+    \namespace QDBusUtil
+    \inmodule QtDBus
+    \internal
+
+    \brief The QDBusUtil namespace contains a few functions that are of general use when
+    dealing with D-Bus strings.
+*/
+namespace QDBusUtil
+{
+    /*!
+        \internal
+        \since 4.5
+        Dumps the contents of a QtDBus argument from \a arg into a string.
+    */
+    QString argumentToString(const QVariant &arg)
+    {
+        QString out;
+
+        variantToString(arg, out);
+
+        return out;
+    }
+
+    /*!
+        \internal
+        \fn bool QDBusUtil::isValidPartOfObjectPath(const QString &part)
+        See QDBusUtil::isValidObjectPath
+    */
+    bool isValidPartOfObjectPath(const QString &part)
+    {
+        if (part.isEmpty())
+            return false;       // can't be valid if it's empty
+
+        const QChar *c = part.unicode();
+        for (int i = 0; i < part.length(); ++i)
+            if (!isValidCharacterNoDash(c[i]))
+                return false;
+
+        return true;
+    }
+
+    /*!
+        \fn bool QDBusUtil::isValidInterfaceName(const QString &ifaceName)
+        Returns true if this is \a ifaceName is a valid interface name.
+
+        Valid interface names must:
+        \list
+          \o not be empty
+          \o not exceed 255 characters in length
+          \o be composed of dot-separated string components that contain only ASCII letters, digits
+             and the underscore ("_") character
+          \o contain at least two such components
+        \endlist
+    */
+    bool isValidInterfaceName(const QString& ifaceName)
+    {
+        if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+            return false;
+
+        QStringList parts = ifaceName.split(QLatin1Char('.'));
+        if (parts.count() < 2)
+            return false;           // at least two parts
+
+        for (int i = 0; i < parts.count(); ++i)
+            if (!isValidMemberName(parts.at(i)))
+                return false;
+
+        return true;
+    }
+
+    /*!
+        \fn bool QDBusUtil::isValidUniqueConnectionName(const QString &connName)
+        Returns true if \a connName is a valid unique connection name.
+
+        Unique connection names start with a colon (":") and are followed by a list of dot-separated
+        components composed of ASCII letters, digits, the hypen or the underscore ("_") character.
+    */
+    bool isValidUniqueConnectionName(const QString &connName)
+    {
+        if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
+            !connName.startsWith(QLatin1Char(':')))
+            return false;
+
+        QStringList parts = connName.mid(1).split(QLatin1Char('.'));
+        if (parts.count() < 1)
+            return false;
+
+        for (int i = 0; i < parts.count(); ++i) {
+            const QString &part = parts.at(i);
+            if (part.isEmpty())
+                 return false;
+
+            const QChar* c = part.unicode();
+            for (int j = 0; j < part.length(); ++j)
+                if (!isValidCharacter(c[j]))
+                    return false;
+        }
+
+        return true;
+    }
+
+    /*!
+        \fn bool QDBusUtil::isValidBusName(const QString &busName)
+        Returns true if \a busName is a valid bus name.
+
+        A valid bus name is either a valid unique connection name or follows the rules:
+        \list
+          \o is not empty
+          \o does not exceed 255 characters in length
+          \o be composed of dot-separated string components that contain only ASCII letters, digits,
+             hyphens or underscores ("_"), but don't start with a digit
+          \o contains at least two such elements
+        \endlist
+
+        \sa isValidUniqueConnectionName()
+    */
+    bool isValidBusName(const QString &busName)
+    {
+        if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+            return false;
+
+        if (busName.startsWith(QLatin1Char(':')))
+            return isValidUniqueConnectionName(busName);
+
+        QStringList parts = busName.split(QLatin1Char('.'));
+        if (parts.count() < 1)
+            return false;
+
+        for (int i = 0; i < parts.count(); ++i) {
+            const QString &part = parts.at(i);
+            if (part.isEmpty())
+                return false;
+
+            const QChar *c = part.unicode();
+            if (isValidNumber(c[0]))
+                return false;
+            for (int j = 0; j < part.length(); ++j)
+                if (!isValidCharacter(c[j]))
+                    return false;
+        }
+
+        return true;
+    }
+
+    /*!
+        \fn bool QDBusUtil::isValidMemberName(const QString &memberName)
+        Returns true if \a memberName is a valid member name. A valid member name does not exceed
+        255 characters in length, is not empty, is composed only of ASCII letters, digits and
+        underscores, but does not start with a digit.
+    */
+    bool isValidMemberName(const QString &memberName)
+    {
+        if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+            return false;
+
+        const QChar* c = memberName.unicode();
+        if (isValidNumber(c[0]))
+            return false;
+        for (int j = 0; j < memberName.length(); ++j)
+            if (!isValidCharacterNoDash(c[j]))
+                return false;
+        return true;
+    }
+
+    /*!
+        \fn bool QDBusUtil::isValidErrorName(const QString &errorName)
+        Returns true if \a errorName is a valid error name. Valid error names are valid interface
+        names and vice-versa, so this function is actually an alias for isValidInterfaceName.
+    */
+    bool isValidErrorName(const QString &errorName)
+    {
+        return isValidInterfaceName(errorName);
+    }
+
+    /*!
+        \fn bool QDBusUtil::isValidObjectPath(const QString &path)
+        Returns true if \a path is valid object path.
+
+        Valid object paths follow the rules:
+        \list
+          \o start with the slash character ("/")
+          \o do not end in a slash, unless the path is just the initial slash
+          \o do not contain any two slashes in sequence
+          \o contain slash-separated parts, each of which is composed of ASCII letters, digits and
+             underscores ("_")
+        \endlist
+    */
+    bool isValidObjectPath(const QString &path)
+    {
+        if (path == QLatin1String("/"))
+            return true;
+
+        if (!path.startsWith(QLatin1Char('/')) || path.indexOf(QLatin1String("//")) != -1 ||
+            path.endsWith(QLatin1Char('/')))
+            return false;
+
+        QStringList parts = path.split(QLatin1Char('/'));
+        Q_ASSERT(parts.count() >= 1);
+        parts.removeFirst();    // it starts with /, so we get an empty first part
+
+        for (int i = 0; i < parts.count(); ++i)
+            if (!isValidPartOfObjectPath(parts.at(i)))
+                return false;
+
+        return true;
+    }
+
+    /*!
+        \fn bool QDBusUtil::isValidSignature(const QString &signature)
+        Returns true if \a signature is a valid D-Bus type signature for one or more types.
+        This function returns true if it can all of \a signature into valid, individual types and no
+        characters remain in \a signature.
+
+        \sa isValidSingleSignature()
+    */
+    bool isValidSignature(const QString &signature)
+    {
+        return q_dbus_signature_validate(signature.toUtf8(), 0);
+    }
+
+    /*!
+        \fn bool QDBusUtil::isValidSingleSignature(const QString &signature)
+        Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This
+        function tries to convert the type signature into a D-Bus type and, if it succeeds and no
+        characters remain in the signature, it returns true.
+    */
+    bool isValidSingleSignature(const QString &signature)
+    {
+        return q_dbus_signature_validate_single(signature.toUtf8(), 0);
+    }
+
+} // namespace QDBusUtil
+
+QT_END_NAMESPACE