|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtDBus module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
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 |
|
50 QT_BEGIN_NAMESPACE |
|
51 |
|
52 static 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 |
|
61 static 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 |
|
70 static inline bool isValidNumber(const QChar &c) |
|
71 { |
|
72 register ushort u = c.unicode(); |
|
73 return (u >= '0' && u <= '9'); |
|
74 } |
|
75 |
|
76 static bool argToString(const QDBusArgument &arg, QString &out); |
|
77 |
|
78 static 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 |
|
155 bool 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 */ |
|
242 namespace 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 |
|
468 QT_END_NAMESPACE |