source: trunk/src/dbus/qdbusutil.cpp@ 807

Last change on this file since 807 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 16.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtDBus module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
50QT_BEGIN_NAMESPACE
51
52static 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
61static 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
70static inline bool isValidNumber(const QChar &c)
71{
72 register ushort u = c.unicode();
73 return (u >= '0' && u <= '9');
74}
75
76static bool argToString(const QDBusArgument &arg, QString &out);
77
78static 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
155bool 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*/
242namespace 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
468QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.