/**************************************************************************** | |
** | |
** Copyright (C) 2011 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$ | |
** GNU Lesser General Public License Usage | |
** 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. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qdbusutil_p.h" | |
#include "qdbus_symbols_p.h" | |
#include <QtCore/qstringlist.h> | |
#include "qdbusargument.h" | |
#ifndef QT_NO_DBUS | |
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 hyphen 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 | |
#endif // QT_NO_DBUS |