9ca80864aa9677cf75d058d36bb7ed80786a15f7
[profile/ivi/qtbase.git] / src / dbus / qdbusutil.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
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 #include "qdbusunixfiledescriptor.h"
50
51 #ifndef QT_NO_DBUS
52
53 QT_BEGIN_NAMESPACE
54
55 static inline bool isValidCharacterNoDash(const QChar &c)
56 {
57     register ushort u = c.unicode();
58     return (u >= 'a' && u <= 'z')
59             || (u >= 'A' && u <= 'Z')
60             || (u >= '0' && u <= '9')
61             || (u == '_');
62 }
63
64 static inline bool isValidCharacter(const QChar &c)
65 {
66     register ushort u = c.unicode();
67     return (u >= 'a' && u <= 'z')
68             || (u >= 'A' && u <= 'Z')
69             || (u >= '0' && u <= '9')
70             || (u == '_') || (u == '-');
71 }
72
73 static inline bool isValidNumber(const QChar &c)
74 {
75     register ushort u = c.unicode();
76     return (u >= '0' && u <= '9');
77 }
78
79 static bool argToString(const QDBusArgument &arg, QString &out);
80
81 static bool variantToString(const QVariant &arg, QString &out)
82 {
83     int argType = arg.userType();
84
85     if (argType == QVariant::StringList) {
86         out += QLatin1Char('{');
87         QStringList list = arg.toStringList();
88         foreach (QString item, list)
89             out += QLatin1Char('\"') + item + QLatin1String("\", ");
90         if (!list.isEmpty())
91             out.chop(2);
92         out += QLatin1Char('}');
93     } else if (argType == QVariant::ByteArray) {
94         out += QLatin1Char('{');
95         QByteArray list = arg.toByteArray();
96         for (int i = 0; i < list.count(); ++i) {
97             out += QString::number(list.at(i));
98             out += QLatin1String(", ");
99         }
100         if (!list.isEmpty())
101             out.chop(2);
102         out += QLatin1Char('}');
103     } else if (argType == QVariant::List) {
104         out += QLatin1Char('{');
105         QList<QVariant> list = arg.toList();
106         foreach (QVariant item, list) {
107             if (!variantToString(item, out))
108                 return false;
109             out += QLatin1String(", ");
110         }
111         if (!list.isEmpty())
112             out.chop(2);
113         out += QLatin1Char('}');
114     } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
115                || argType == QMetaType::Long || argType == QMetaType::LongLong) {
116         out += QString::number(arg.toLongLong());
117     } else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
118                || argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
119         out += QString::number(arg.toULongLong());
120     } else if (argType == QMetaType::Double) {
121         out += QString::number(arg.toDouble());
122     } else if (argType == QMetaType::Bool) {
123         out += QLatin1String(arg.toBool() ? "true" : "false");
124     } else if (argType == qMetaTypeId<QDBusArgument>()) {
125         argToString(qvariant_cast<QDBusArgument>(arg), out);
126     } else if (argType == qMetaTypeId<QDBusObjectPath>()) {
127         const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
128         out += QLatin1String("[ObjectPath: ");
129         out += path;
130         out += QLatin1Char(']');
131     } else if (argType == qMetaTypeId<QDBusSignature>()) {
132         out += QLatin1String("[Signature: ") + qvariant_cast<QDBusSignature>(arg).signature();
133         out += QLatin1Char(']');
134     } else if (argType == qMetaTypeId<QDBusUnixFileDescriptor>()) {
135         out += QLatin1String("[Unix FD: ");
136         out += QLatin1String(qvariant_cast<QDBusUnixFileDescriptor>(arg).isValid() ? "valid" : "not valid");
137         out += QLatin1Char(']');
138     } else if (argType == qMetaTypeId<QDBusVariant>()) {
139         const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
140         out += QLatin1String("[Variant");
141         int vUserType = v.userType();
142         if (vUserType != qMetaTypeId<QDBusVariant>()
143                 && vUserType != qMetaTypeId<QDBusSignature>()
144                 && vUserType != qMetaTypeId<QDBusObjectPath>()
145                 && vUserType != qMetaTypeId<QDBusArgument>())
146             out += QLatin1Char('(') + QLatin1String(v.typeName()) + QLatin1Char(')');
147         out += QLatin1String(": ");
148         if (!variantToString(v, out))
149             return false;
150         out += QLatin1Char(']');
151     } else if (arg.canConvert(QVariant::String)) {
152         out += QLatin1Char('\"') + arg.toString() + QLatin1Char('\"');
153     } else {
154         out += QLatin1Char('[');
155         out += QLatin1String(arg.typeName());
156         out += QLatin1Char(']');
157     }
158
159     return true;
160 }
161
162 bool argToString(const QDBusArgument &busArg, QString &out)
163 {
164     QString busSig = busArg.currentSignature();
165     bool doIterate = false;
166     QDBusArgument::ElementType elementType = busArg.currentType();
167
168     if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
169             && elementType != QDBusArgument::MapEntryType)
170         out += QLatin1String("[Argument: ") + busSig + QLatin1Char(' ');
171
172     switch (elementType) {
173         case QDBusArgument::BasicType:
174         case QDBusArgument::VariantType:
175             if (!variantToString(busArg.asVariant(), out))
176                 return false;
177             break;
178         case QDBusArgument::StructureType:
179             busArg.beginStructure();
180             doIterate = true;
181             break;
182         case QDBusArgument::ArrayType:
183             busArg.beginArray();
184             out += QLatin1Char('{');
185             doIterate = true;
186             break;
187         case QDBusArgument::MapType:
188             busArg.beginMap();
189             out += QLatin1Char('{');
190             doIterate = true;
191             break;
192         case QDBusArgument::MapEntryType:
193             busArg.beginMapEntry();
194             if (!variantToString(busArg.asVariant(), out))
195                 return false;
196             out += QLatin1String(" = ");
197             if (!argToString(busArg, out))
198                 return false;
199             busArg.endMapEntry();
200             break;
201         case QDBusArgument::UnknownType:
202         default:
203             out += QLatin1String("<ERROR - Unknown Type>");
204             return false;
205     }
206     if (doIterate && !busArg.atEnd()) {
207         while (!busArg.atEnd()) {
208             if (!argToString(busArg, out))
209                 return false;
210             out += QLatin1String(", ");
211         }
212         out.chop(2);
213     }
214     switch (elementType) {
215         case QDBusArgument::BasicType:
216         case QDBusArgument::VariantType:
217         case QDBusArgument::UnknownType:
218         case QDBusArgument::MapEntryType:
219             // nothing to do
220             break;
221         case QDBusArgument::StructureType:
222             busArg.endStructure();
223             break;
224         case QDBusArgument::ArrayType:
225             out += QLatin1Char('}');
226             busArg.endArray();
227             break;
228         case QDBusArgument::MapType:
229             out += QLatin1Char('}');
230             busArg.endMap();
231             break;
232     }
233
234     if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
235             && elementType != QDBusArgument::MapEntryType)
236         out += QLatin1Char(']');
237
238     return true;
239 }
240
241 //------- D-Bus Types --------
242 static const char oneLetterTypes[] = "vsogybnqiuxtdh";
243 static const char basicTypes[] =      "sogybnqiuxtdh";
244 static const char fixedTypes[] =         "ybnqiuxtdh";
245
246 static bool isBasicType(int c)
247 {
248     return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != NULL;
249 }
250
251 static bool isFixedType(int c)
252 {
253     return c != DBUS_TYPE_INVALID && strchr(fixedTypes, c) != NULL;
254 }
255
256 // Returns a pointer to one-past-end of this type if it's valid;
257 // returns NULL if it isn't valid.
258 static const char *validateSingleType(const char *signature)
259 {
260     register char c = *signature;
261     if (c == DBUS_TYPE_INVALID)
262         return 0;
263
264     // is it one of the one-letter types?
265     if (strchr(oneLetterTypes, c) != NULL)
266         return signature + 1;
267
268     // is it an array?
269     if (c == DBUS_TYPE_ARRAY) {
270         // then it's valid if the next type is valid
271         // or if it's a dict-entry
272         c = *++signature;
273         if (c == DBUS_DICT_ENTRY_BEGIN_CHAR) {
274             // beginning of a dictionary entry
275             // a dictionary entry has a key which is of basic types
276             // and a free value
277             c = *++signature;
278             if (!isBasicType(c))
279                 return 0;
280             signature = validateSingleType(signature + 1);
281             return signature && *signature == DBUS_DICT_ENTRY_END_CHAR ? signature + 1 : 0;
282         }
283
284         return validateSingleType(signature);
285     }
286
287     if (c == DBUS_STRUCT_BEGIN_CHAR) {
288         // beginning of a struct
289         ++signature;
290         while (true) {
291             signature = validateSingleType(signature);
292             if (!signature)
293                 return 0;
294             if (*signature == DBUS_STRUCT_END_CHAR)
295                 return signature + 1;
296         }
297     }
298
299     // invalid/unknown type
300     return 0;
301 }
302
303 /*!
304     \namespace QDBusUtil
305     \inmodule QtDBus
306     \internal
307
308     \brief The QDBusUtil namespace contains a few functions that are of general use when
309     dealing with D-Bus strings.
310 */
311 namespace QDBusUtil
312 {
313     /*!
314         \internal
315         \since 4.5
316         Dumps the contents of a QtDBus argument from \a arg into a string.
317     */
318     QString argumentToString(const QVariant &arg)
319     {
320         QString out;
321
322         variantToString(arg, out);
323
324         return out;
325     }
326
327     /*!
328         \internal
329         \fn bool QDBusUtil::isValidPartOfObjectPath(const QString &part)
330         See QDBusUtil::isValidObjectPath
331     */
332     bool isValidPartOfObjectPath(const QString &part)
333     {
334         if (part.isEmpty())
335             return false;       // can't be valid if it's empty
336
337         const QChar *c = part.unicode();
338         for (int i = 0; i < part.length(); ++i)
339             if (!isValidCharacterNoDash(c[i]))
340                 return false;
341
342         return true;
343     }
344
345     /*!
346         \fn bool QDBusUtil::isValidInterfaceName(const QString &ifaceName)
347         Returns true if this is \a ifaceName is a valid interface name.
348
349         Valid interface names must:
350         \list
351           \o not be empty
352           \o not exceed 255 characters in length
353           \o be composed of dot-separated string components that contain only ASCII letters, digits
354              and the underscore ("_") character
355           \o contain at least two such components
356         \endlist
357     */
358     bool isValidInterfaceName(const QString& ifaceName)
359     {
360         if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
361             return false;
362
363         QStringList parts = ifaceName.split(QLatin1Char('.'));
364         if (parts.count() < 2)
365             return false;           // at least two parts
366
367         for (int i = 0; i < parts.count(); ++i)
368             if (!isValidMemberName(parts.at(i)))
369                 return false;
370
371         return true;
372     }
373
374     /*!
375         \fn bool QDBusUtil::isValidUniqueConnectionName(const QString &connName)
376         Returns true if \a connName is a valid unique connection name.
377
378         Unique connection names start with a colon (":") and are followed by a list of dot-separated
379         components composed of ASCII letters, digits, the hyphen or the underscore ("_") character.
380     */
381     bool isValidUniqueConnectionName(const QString &connName)
382     {
383         if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
384             !connName.startsWith(QLatin1Char(':')))
385             return false;
386
387         QStringList parts = connName.mid(1).split(QLatin1Char('.'));
388         if (parts.count() < 1)
389             return false;
390
391         for (int i = 0; i < parts.count(); ++i) {
392             const QString &part = parts.at(i);
393             if (part.isEmpty())
394                  return false;
395
396             const QChar* c = part.unicode();
397             for (int j = 0; j < part.length(); ++j)
398                 if (!isValidCharacter(c[j]))
399                     return false;
400         }
401
402         return true;
403     }
404
405     /*!
406         \fn bool QDBusUtil::isValidBusName(const QString &busName)
407         Returns true if \a busName is a valid bus name.
408
409         A valid bus name is either a valid unique connection name or follows the rules:
410         \list
411           \o is not empty
412           \o does not exceed 255 characters in length
413           \o be composed of dot-separated string components that contain only ASCII letters, digits,
414              hyphens or underscores ("_"), but don't start with a digit
415           \o contains at least two such elements
416         \endlist
417
418         \sa isValidUniqueConnectionName()
419     */
420     bool isValidBusName(const QString &busName)
421     {
422         if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
423             return false;
424
425         if (busName.startsWith(QLatin1Char(':')))
426             return isValidUniqueConnectionName(busName);
427
428         QStringList parts = busName.split(QLatin1Char('.'));
429         if (parts.count() < 1)
430             return false;
431
432         for (int i = 0; i < parts.count(); ++i) {
433             const QString &part = parts.at(i);
434             if (part.isEmpty())
435                 return false;
436
437             const QChar *c = part.unicode();
438             if (isValidNumber(c[0]))
439                 return false;
440             for (int j = 0; j < part.length(); ++j)
441                 if (!isValidCharacter(c[j]))
442                     return false;
443         }
444
445         return true;
446     }
447
448     /*!
449         \fn bool QDBusUtil::isValidMemberName(const QString &memberName)
450         Returns true if \a memberName is a valid member name. A valid member name does not exceed
451         255 characters in length, is not empty, is composed only of ASCII letters, digits and
452         underscores, but does not start with a digit.
453     */
454     bool isValidMemberName(const QString &memberName)
455     {
456         if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
457             return false;
458
459         const QChar* c = memberName.unicode();
460         if (isValidNumber(c[0]))
461             return false;
462         for (int j = 0; j < memberName.length(); ++j)
463             if (!isValidCharacterNoDash(c[j]))
464                 return false;
465         return true;
466     }
467
468     /*!
469         \fn bool QDBusUtil::isValidErrorName(const QString &errorName)
470         Returns true if \a errorName is a valid error name. Valid error names are valid interface
471         names and vice-versa, so this function is actually an alias for isValidInterfaceName.
472     */
473     bool isValidErrorName(const QString &errorName)
474     {
475         return isValidInterfaceName(errorName);
476     }
477
478     /*!
479         \fn bool QDBusUtil::isValidObjectPath(const QString &path)
480         Returns true if \a path is valid object path.
481
482         Valid object paths follow the rules:
483         \list
484           \o start with the slash character ("/")
485           \o do not end in a slash, unless the path is just the initial slash
486           \o do not contain any two slashes in sequence
487           \o contain slash-separated parts, each of which is composed of ASCII letters, digits and
488              underscores ("_")
489         \endlist
490     */
491     bool isValidObjectPath(const QString &path)
492     {
493         if (path == QLatin1String("/"))
494             return true;
495
496         if (!path.startsWith(QLatin1Char('/')) || path.indexOf(QLatin1String("//")) != -1 ||
497             path.endsWith(QLatin1Char('/')))
498             return false;
499
500         QStringList parts = path.split(QLatin1Char('/'));
501         Q_ASSERT(parts.count() >= 1);
502         parts.removeFirst();    // it starts with /, so we get an empty first part
503
504         for (int i = 0; i < parts.count(); ++i)
505             if (!isValidPartOfObjectPath(parts.at(i)))
506                 return false;
507
508         return true;
509     }
510
511     /*!
512         \fn bool QDBusUtil::isValidBasicType(int type)
513         Returns true if \a c is a valid, basic D-Bus type.
514      */
515     bool isValidBasicType(int c)
516     {
517         return isBasicType(c);
518     }
519
520     /*!
521         \fn bool QDBusUtil::isValidFixedType(int type)
522         Returns true if \a c is a valid, fixed D-Bus type.
523      */
524     bool isValidFixedType(int c)
525     {
526         return isFixedType(c);
527     }
528
529
530     /*!
531         \fn bool QDBusUtil::isValidSignature(const QString &signature)
532         Returns true if \a signature is a valid D-Bus type signature for one or more types.
533         This function returns true if it can all of \a signature into valid, individual types and no
534         characters remain in \a signature.
535
536         \sa isValidSingleSignature()
537     */
538     bool isValidSignature(const QString &signature)
539     {
540         QByteArray ba = signature.toLatin1();
541         const char *data = ba.constData();
542         while (true) {
543             data = validateSingleType(data);
544             if (!data)
545                 return false;
546             if (*data == '\0')
547                 return true;
548         }
549     }
550
551     /*!
552         \fn bool QDBusUtil::isValidSingleSignature(const QString &signature)
553         Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This
554         function tries to convert the type signature into a D-Bus type and, if it succeeds and no
555         characters remain in the signature, it returns true.
556     */
557     bool isValidSingleSignature(const QString &signature)
558     {
559         QByteArray ba = signature.toLatin1();
560         const char *data = validateSingleType(ba.constData());
561         return data && *data == '\0';
562     }
563
564 } // namespace QDBusUtil
565
566 QT_END_NAMESPACE
567
568 #endif // QT_NO_DBUS