src/dbus/qdbusutil.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDBus module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qdbusutil_p.h"
       
    43 
       
    44 #include <qdbus_symbols_p.h>
       
    45 
       
    46 #include <QtCore/qstringlist.h>
       
    47 
       
    48 #include "qdbusargument.h"
       
    49 
       
    50 QT_BEGIN_NAMESPACE
       
    51 
       
    52 static inline bool isValidCharacterNoDash(const QChar &c)
       
    53 {
       
    54     register ushort u = c.unicode();
       
    55     return (u >= 'a' && u <= 'z')
       
    56             || (u >= 'A' && u <= 'Z')
       
    57             || (u >= '0' && u <= '9')
       
    58             || (u == '_');
       
    59 }
       
    60 
       
    61 static inline bool isValidCharacter(const QChar &c)
       
    62 {
       
    63     register ushort u = c.unicode();
       
    64     return (u >= 'a' && u <= 'z')
       
    65             || (u >= 'A' && u <= 'Z')
       
    66             || (u >= '0' && u <= '9')
       
    67             || (u == '_') || (u == '-');
       
    68 }
       
    69 
       
    70 static inline bool isValidNumber(const QChar &c)
       
    71 {
       
    72     register ushort u = c.unicode();
       
    73     return (u >= '0' && u <= '9');
       
    74 }
       
    75 
       
    76 static bool argToString(const QDBusArgument &arg, QString &out);
       
    77 
       
    78 static bool variantToString(const QVariant &arg, QString &out)
       
    79 {
       
    80     int argType = arg.userType();
       
    81 
       
    82     if (argType == QVariant::StringList) {
       
    83         out += QLatin1Char('{');
       
    84         QStringList list = arg.toStringList();
       
    85         foreach (QString item, list)
       
    86             out += QLatin1Char('\"') + item + QLatin1String("\", ");
       
    87         if (!list.isEmpty())
       
    88             out.chop(2);
       
    89         out += QLatin1Char('}');
       
    90     } else if (argType == QVariant::ByteArray) {
       
    91         out += QLatin1Char('{');
       
    92         QByteArray list = arg.toByteArray();
       
    93         for (int i = 0; i < list.count(); ++i) {
       
    94             out += QString::number(list.at(i));
       
    95             out += QLatin1String(", ");
       
    96         }
       
    97         if (!list.isEmpty())
       
    98             out.chop(2);
       
    99         out += QLatin1Char('}');
       
   100     } else if (argType == QVariant::List) {
       
   101         out += QLatin1Char('{');
       
   102         QList<QVariant> list = arg.toList();
       
   103         foreach (QVariant item, list) {
       
   104             if (!variantToString(item, out))
       
   105                 return false;
       
   106             out += QLatin1String(", ");
       
   107         }
       
   108         if (!list.isEmpty())
       
   109             out.chop(2);
       
   110         out += QLatin1Char('}');
       
   111     } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
       
   112                || argType == QMetaType::Long || argType == QMetaType::LongLong) {
       
   113         out += QString::number(arg.toLongLong());
       
   114     } else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
       
   115                || argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
       
   116         out += QString::number(arg.toULongLong());
       
   117     } else if (argType == QMetaType::Double) {
       
   118         out += QString::number(arg.toDouble());
       
   119     } else if (argType == QMetaType::Bool) {
       
   120         out += QLatin1String(arg.toBool() ? "true" : "false");
       
   121     } else if (argType == qMetaTypeId<QDBusArgument>()) {
       
   122         argToString(qvariant_cast<QDBusArgument>(arg), out);
       
   123     } else if (argType == qMetaTypeId<QDBusObjectPath>()) {
       
   124         const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
       
   125         out += QLatin1String("[ObjectPath: ");
       
   126         out += path;
       
   127         out += QLatin1Char(']');
       
   128     } else if (argType == qMetaTypeId<QDBusSignature>()) {
       
   129         out += QLatin1String("[Signature: ") + qvariant_cast<QDBusSignature>(arg).signature();
       
   130         out += QLatin1Char(']');
       
   131     } else if (argType == qMetaTypeId<QDBusVariant>()) {
       
   132         const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
       
   133         out += QLatin1String("[Variant");
       
   134         int vUserType = v.userType();
       
   135         if (vUserType != qMetaTypeId<QDBusVariant>()
       
   136                 && vUserType != qMetaTypeId<QDBusSignature>()
       
   137                 && vUserType != qMetaTypeId<QDBusObjectPath>()
       
   138                 && vUserType != qMetaTypeId<QDBusArgument>())
       
   139             out += QLatin1Char('(') + QLatin1String(v.typeName()) + QLatin1Char(')');
       
   140         out += QLatin1String(": ");
       
   141         if (!variantToString(v, out))
       
   142             return false;
       
   143         out += QLatin1Char(']');
       
   144     } else if (arg.canConvert(QVariant::String)) {
       
   145         out += QLatin1Char('\"') + arg.toString() + QLatin1Char('\"');
       
   146     } else {
       
   147         out += QLatin1Char('[');
       
   148         out += QLatin1String(arg.typeName());
       
   149         out += QLatin1Char(']');
       
   150     }
       
   151 
       
   152     return true;
       
   153 }
       
   154 
       
   155 bool argToString(const QDBusArgument &busArg, QString &out)
       
   156 {
       
   157     QString busSig = busArg.currentSignature();
       
   158     bool doIterate = false;
       
   159     QDBusArgument::ElementType elementType = busArg.currentType();
       
   160 
       
   161     if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
       
   162             && elementType != QDBusArgument::MapEntryType)
       
   163         out += QLatin1String("[Argument: ") + busSig + QLatin1Char(' ');
       
   164 
       
   165     switch (elementType) {
       
   166         case QDBusArgument::BasicType:
       
   167         case QDBusArgument::VariantType:
       
   168             if (!variantToString(busArg.asVariant(), out))
       
   169                 return false;
       
   170             break;
       
   171         case QDBusArgument::StructureType:
       
   172             busArg.beginStructure();
       
   173             doIterate = true;
       
   174             break;
       
   175         case QDBusArgument::ArrayType:
       
   176             busArg.beginArray();
       
   177             out += QLatin1Char('{');
       
   178             doIterate = true;
       
   179             break;
       
   180         case QDBusArgument::MapType:
       
   181             busArg.beginMap();
       
   182             out += QLatin1Char('{');
       
   183             doIterate = true;
       
   184             break;
       
   185         case QDBusArgument::MapEntryType:
       
   186             busArg.beginMapEntry();
       
   187             if (!variantToString(busArg.asVariant(), out))
       
   188                 return false;
       
   189             out += QLatin1String(" = ");
       
   190             if (!argToString(busArg, out))
       
   191                 return false;
       
   192             busArg.endMapEntry();
       
   193             break;
       
   194         case QDBusArgument::UnknownType:
       
   195         default:
       
   196             out += QLatin1String("<ERROR - Unknown Type>");
       
   197             return false;
       
   198     }
       
   199     if (doIterate && !busArg.atEnd()) {
       
   200         while (!busArg.atEnd()) {
       
   201             if (!argToString(busArg, out))
       
   202                 return false;
       
   203             out += QLatin1String(", ");
       
   204         }
       
   205         out.chop(2);
       
   206     }
       
   207     switch (elementType) {
       
   208         case QDBusArgument::BasicType:
       
   209         case QDBusArgument::VariantType:
       
   210         case QDBusArgument::UnknownType:
       
   211         case QDBusArgument::MapEntryType:
       
   212             // nothing to do
       
   213             break;
       
   214         case QDBusArgument::StructureType:
       
   215             busArg.endStructure();
       
   216             break;
       
   217         case QDBusArgument::ArrayType:
       
   218             out += QLatin1Char('}');
       
   219             busArg.endArray();
       
   220             break;
       
   221         case QDBusArgument::MapType:
       
   222             out += QLatin1Char('}');
       
   223             busArg.endMap();
       
   224             break;
       
   225     }
       
   226 
       
   227     if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
       
   228             && elementType != QDBusArgument::MapEntryType)
       
   229         out += QLatin1Char(']');
       
   230 
       
   231     return true;
       
   232 }
       
   233 
       
   234 /*!
       
   235     \namespace QDBusUtil
       
   236     \inmodule QtDBus
       
   237     \internal
       
   238 
       
   239     \brief The QDBusUtil namespace contains a few functions that are of general use when
       
   240     dealing with D-Bus strings.
       
   241 */
       
   242 namespace QDBusUtil
       
   243 {
       
   244     /*!
       
   245         \internal
       
   246         \since 4.5
       
   247         Dumps the contents of a QtDBus argument from \a arg into a string.
       
   248     */
       
   249     QString argumentToString(const QVariant &arg)
       
   250     {
       
   251         QString out;
       
   252 
       
   253         variantToString(arg, out);
       
   254 
       
   255         return out;
       
   256     }
       
   257 
       
   258     /*!
       
   259         \internal
       
   260         \fn bool QDBusUtil::isValidPartOfObjectPath(const QString &part)
       
   261         See QDBusUtil::isValidObjectPath
       
   262     */
       
   263     bool isValidPartOfObjectPath(const QString &part)
       
   264     {
       
   265         if (part.isEmpty())
       
   266             return false;       // can't be valid if it's empty
       
   267 
       
   268         const QChar *c = part.unicode();
       
   269         for (int i = 0; i < part.length(); ++i)
       
   270             if (!isValidCharacterNoDash(c[i]))
       
   271                 return false;
       
   272 
       
   273         return true;
       
   274     }
       
   275 
       
   276     /*!
       
   277         \fn bool QDBusUtil::isValidInterfaceName(const QString &ifaceName)
       
   278         Returns true if this is \a ifaceName is a valid interface name.
       
   279 
       
   280         Valid interface names must:
       
   281         \list
       
   282           \o not be empty
       
   283           \o not exceed 255 characters in length
       
   284           \o be composed of dot-separated string components that contain only ASCII letters, digits
       
   285              and the underscore ("_") character
       
   286           \o contain at least two such components
       
   287         \endlist
       
   288     */
       
   289     bool isValidInterfaceName(const QString& ifaceName)
       
   290     {
       
   291         if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
       
   292             return false;
       
   293 
       
   294         QStringList parts = ifaceName.split(QLatin1Char('.'));
       
   295         if (parts.count() < 2)
       
   296             return false;           // at least two parts
       
   297 
       
   298         for (int i = 0; i < parts.count(); ++i)
       
   299             if (!isValidMemberName(parts.at(i)))
       
   300                 return false;
       
   301 
       
   302         return true;
       
   303     }
       
   304 
       
   305     /*!
       
   306         \fn bool QDBusUtil::isValidUniqueConnectionName(const QString &connName)
       
   307         Returns true if \a connName is a valid unique connection name.
       
   308 
       
   309         Unique connection names start with a colon (":") and are followed by a list of dot-separated
       
   310         components composed of ASCII letters, digits, the hypen or the underscore ("_") character.
       
   311     */
       
   312     bool isValidUniqueConnectionName(const QString &connName)
       
   313     {
       
   314         if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
       
   315             !connName.startsWith(QLatin1Char(':')))
       
   316             return false;
       
   317 
       
   318         QStringList parts = connName.mid(1).split(QLatin1Char('.'));
       
   319         if (parts.count() < 1)
       
   320             return false;
       
   321 
       
   322         for (int i = 0; i < parts.count(); ++i) {
       
   323             const QString &part = parts.at(i);
       
   324             if (part.isEmpty())
       
   325                  return false;
       
   326 
       
   327             const QChar* c = part.unicode();
       
   328             for (int j = 0; j < part.length(); ++j)
       
   329                 if (!isValidCharacter(c[j]))
       
   330                     return false;
       
   331         }
       
   332 
       
   333         return true;
       
   334     }
       
   335 
       
   336     /*!
       
   337         \fn bool QDBusUtil::isValidBusName(const QString &busName)
       
   338         Returns true if \a busName is a valid bus name.
       
   339 
       
   340         A valid bus name is either a valid unique connection name or follows the rules:
       
   341         \list
       
   342           \o is not empty
       
   343           \o does not exceed 255 characters in length
       
   344           \o be composed of dot-separated string components that contain only ASCII letters, digits,
       
   345              hyphens or underscores ("_"), but don't start with a digit
       
   346           \o contains at least two such elements
       
   347         \endlist
       
   348 
       
   349         \sa isValidUniqueConnectionName()
       
   350     */
       
   351     bool isValidBusName(const QString &busName)
       
   352     {
       
   353         if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
       
   354             return false;
       
   355 
       
   356         if (busName.startsWith(QLatin1Char(':')))
       
   357             return isValidUniqueConnectionName(busName);
       
   358 
       
   359         QStringList parts = busName.split(QLatin1Char('.'));
       
   360         if (parts.count() < 1)
       
   361             return false;
       
   362 
       
   363         for (int i = 0; i < parts.count(); ++i) {
       
   364             const QString &part = parts.at(i);
       
   365             if (part.isEmpty())
       
   366                 return false;
       
   367 
       
   368             const QChar *c = part.unicode();
       
   369             if (isValidNumber(c[0]))
       
   370                 return false;
       
   371             for (int j = 0; j < part.length(); ++j)
       
   372                 if (!isValidCharacter(c[j]))
       
   373                     return false;
       
   374         }
       
   375 
       
   376         return true;
       
   377     }
       
   378 
       
   379     /*!
       
   380         \fn bool QDBusUtil::isValidMemberName(const QString &memberName)
       
   381         Returns true if \a memberName is a valid member name. A valid member name does not exceed
       
   382         255 characters in length, is not empty, is composed only of ASCII letters, digits and
       
   383         underscores, but does not start with a digit.
       
   384     */
       
   385     bool isValidMemberName(const QString &memberName)
       
   386     {
       
   387         if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
       
   388             return false;
       
   389 
       
   390         const QChar* c = memberName.unicode();
       
   391         if (isValidNumber(c[0]))
       
   392             return false;
       
   393         for (int j = 0; j < memberName.length(); ++j)
       
   394             if (!isValidCharacterNoDash(c[j]))
       
   395                 return false;
       
   396         return true;
       
   397     }
       
   398 
       
   399     /*!
       
   400         \fn bool QDBusUtil::isValidErrorName(const QString &errorName)
       
   401         Returns true if \a errorName is a valid error name. Valid error names are valid interface
       
   402         names and vice-versa, so this function is actually an alias for isValidInterfaceName.
       
   403     */
       
   404     bool isValidErrorName(const QString &errorName)
       
   405     {
       
   406         return isValidInterfaceName(errorName);
       
   407     }
       
   408 
       
   409     /*!
       
   410         \fn bool QDBusUtil::isValidObjectPath(const QString &path)
       
   411         Returns true if \a path is valid object path.
       
   412 
       
   413         Valid object paths follow the rules:
       
   414         \list
       
   415           \o start with the slash character ("/")
       
   416           \o do not end in a slash, unless the path is just the initial slash
       
   417           \o do not contain any two slashes in sequence
       
   418           \o contain slash-separated parts, each of which is composed of ASCII letters, digits and
       
   419              underscores ("_")
       
   420         \endlist
       
   421     */
       
   422     bool isValidObjectPath(const QString &path)
       
   423     {
       
   424         if (path == QLatin1String("/"))
       
   425             return true;
       
   426 
       
   427         if (!path.startsWith(QLatin1Char('/')) || path.indexOf(QLatin1String("//")) != -1 ||
       
   428             path.endsWith(QLatin1Char('/')))
       
   429             return false;
       
   430 
       
   431         QStringList parts = path.split(QLatin1Char('/'));
       
   432         Q_ASSERT(parts.count() >= 1);
       
   433         parts.removeFirst();    // it starts with /, so we get an empty first part
       
   434 
       
   435         for (int i = 0; i < parts.count(); ++i)
       
   436             if (!isValidPartOfObjectPath(parts.at(i)))
       
   437                 return false;
       
   438 
       
   439         return true;
       
   440     }
       
   441 
       
   442     /*!
       
   443         \fn bool QDBusUtil::isValidSignature(const QString &signature)
       
   444         Returns true if \a signature is a valid D-Bus type signature for one or more types.
       
   445         This function returns true if it can all of \a signature into valid, individual types and no
       
   446         characters remain in \a signature.
       
   447 
       
   448         \sa isValidSingleSignature()
       
   449     */
       
   450     bool isValidSignature(const QString &signature)
       
   451     {
       
   452         return q_dbus_signature_validate(signature.toUtf8(), 0);
       
   453     }
       
   454 
       
   455     /*!
       
   456         \fn bool QDBusUtil::isValidSingleSignature(const QString &signature)
       
   457         Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This
       
   458         function tries to convert the type signature into a D-Bus type and, if it succeeds and no
       
   459         characters remain in the signature, it returns true.
       
   460     */
       
   461     bool isValidSingleSignature(const QString &signature)
       
   462     {
       
   463         return q_dbus_signature_validate_single(signature.toUtf8(), 0);
       
   464     }
       
   465 
       
   466 } // namespace QDBusUtil
       
   467 
       
   468 QT_END_NAMESPACE