~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/dbus/qdbusutil.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtDBus module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 2.1 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
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