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