* dbus/dbus-sysdeps.c: Make tcp socket connection error somewhat more
[platform/upstream/dbus.git] / qt / src / qdbustype.cpp
1 /* -*- C++ -*-
2  *
3  * Copyright (C) 2005 Thiago Macieira <thiago@kde.org>
4  * Copyright (C) 2006 Trolltech AS. All rights reserved.
5  *    Author: Thiago Macieira <thiago.macieira@trolltech.com>
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "qdbustype_p.h"
26 #include "qdbustypehelper_p.h"
27 #include <dbus/dbus.h>
28
29 #include <QtCore/qstringlist.h>
30
31 class QDBusTypePrivate: public QSharedData
32 {
33 public:
34     int code;
35     mutable int qvariantType;
36     mutable QByteArray signature;
37     QDBusTypeList subTypes;
38
39     inline QDBusTypePrivate()
40         : code(0), qvariantType(QVariant::Invalid)
41     { }
42 };
43
44 /*!
45     \class QDBusType
46     \brief Represents one single D-Bus type.
47     \internal
48
49     D-Bus provides a set of primitive types that map to normal, C++ types and to QString, as well as
50     the possibility to extend the set with the so-called "container" types. The available types are
51     as follows:
52
53     - Primitive (or basic): integers of 16, 32 and 64 bits, both signed and unsigned; byte (8 bits);
54       double-precision floating point and Unicode strings
55     - Arrays: a homogeneous, ordered list of zero or more entries
56     - Maps: an unordered list of (key, value) pairs, where key must be a primitive type and value
57       can be any D-Bus type
58     - Structs: an ordered list of a fixed number of entries of any type
59     - Variants: a "wildcard" container that can assume the value of any other type, including
60       structs and arrays
61
62     Any type can be placed inside an array (including other arrays), but only entries of the same
63     type can be placed inside the same array. The analogous type for D-Bus arrays are the Qt
64     #QList template classes.
65
66     Structs have a fixed number of entries and each entry has a fixed type. They are analogous to C
67     and C++ structs (hence the name).
68
69     Maps or dictionaries are analogous to the Qt #QMap template class, with the additional
70     restriction that the key type must be a primitive one. D-Bus implements maps by using arrays of
71     a special type (a "dictionary entry"), so inspecting a QDBusType of a Map will reveal that it is
72     an array (see isArray()).
73
74     Variants contain exactly one entry, but the type can vary freely. It is analogous to the Qt
75     class #QVariant, but the QtDBus implementation uses #QDBusVariant to represent D-Bus Variants.
76 */
77
78 /*!
79     Constructs an empty (invalid) type.
80 */
81 QDBusType::QDBusType()
82     : d(0)
83 {
84 }
85
86 /*!
87     Constructs the type based on the D-Bus type given by \a type.
88 */
89 QDBusType::QDBusType(int type)
90 {
91     char c[2] = { type, 0 };
92     *this = QDBusType(c);
93 }
94
95 /*!
96     Constructs the type based on the QVariant type given by \a type.
97
98     \sa QVariant::Type
99 */
100 QDBusType::QDBusType(QVariant::Type type)
101 {
102     const char *sig = dbusSignature(type);
103
104     // it never returns NULL
105     // but it may return an empty string:
106     if (sig[0] == '\0')
107         return;
108
109     if (qstrlen(sig) > 2) {
110         *this = QDBusType(sig);
111     } else {
112         d = new QDBusTypePrivate;
113         d->qvariantType = type;
114         d->code = sig[0];
115         if (sig[1] == '\0')
116             // single-letter type
117             return;
118         else {
119             // two-letter type
120             // must be an array
121             d->code = sig[0];
122             QDBusType t;
123             t.d = new QDBusTypePrivate;
124             t.d->code = sig[1];
125             d->subTypes << t;
126         }
127     }
128 }
129
130 /*!
131     Parses the D-Bus signature given by \a signature and constructs the type it represents.
132 */
133 QDBusType::QDBusType(const char* signature)
134 {
135     if ( !dbus_signature_validate_single(signature, 0) )
136         return;
137
138     DBusSignatureIter iter;
139     dbus_signature_iter_init(&iter, signature);
140     *this = QDBusType(&iter);
141     if (d)
142         d->signature = signature;
143 }
144
145 /*!
146     \overload
147     Parses the D-Bus signature given by \a str and constructs the type it represents.
148 */
149 QDBusType::QDBusType(const QString& str)
150 {
151     *this = QDBusType( str.toUtf8().constData() );
152 }
153
154 /*!
155     \overload 
156     Parses the D-Bus signature given by \a str and constructs the type it represents.
157 */
158 QDBusType::QDBusType(const QByteArray& str)
159 {
160     *this = QDBusType( str.constData() );
161 }
162
163 /*!
164     \internal
165     Creates a QDBusType object based on the current element pointed to by \a iter.
166 */
167 QDBusType::QDBusType(DBusSignatureIter* iter)
168     : d(new QDBusTypePrivate)
169 {
170     if ( dbus_type_is_container( d->code = dbus_signature_iter_get_current_type(iter) ) ) {
171         // we have to recurse
172         if ( d->code == DBUS_TYPE_VARIANT )
173             return;             // no we don't. dbus_type_is_container lies to us
174
175         // we have to recurse
176         DBusSignatureIter subiter;
177         dbus_signature_iter_recurse(iter, &subiter);
178
179         d->subTypes = QDBusTypeList(&subiter);
180
181         // sanity checking:
182         if ( d->code == DBUS_TYPE_ARRAY )
183             Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType",
184                        "more than one element in array");
185         else if (d->code == DBUS_TYPE_DICT_ENTRY )
186             Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType",
187                        "maps must have exactly two elements");
188     }
189 }
190
191 /*!
192     Copies the type from the object \a other.
193 */
194 QDBusType::QDBusType(const QDBusType& other)
195     : d(other.d)
196 {
197 }
198
199 /*!
200     Release the resources associated with this type.
201 */
202 QDBusType::~QDBusType()
203 {
204 }
205
206 /*!
207     Copies the type from the object given by \a other.
208 */
209 QDBusType& QDBusType::operator=(const QDBusType& other)
210 {
211     d = other.d;
212     return *this;
213 }
214
215 /*!
216     Returns the DBus type for this type.
217 */
218 int QDBusType::dbusType() const
219 {
220     return d ? d->code : DBUS_TYPE_INVALID;
221 }
222
223 /*!
224     Returns the DBus signature for this type and subtypes.
225 */
226 QByteArray QDBusType::dbusSignature() const
227 {
228     if (!d)
229         return QByteArray();
230
231     if (!d->signature.isEmpty())
232         return d->signature;
233
234     if (d->subTypes.isEmpty())
235         return d->signature = QByteArray(1, d->code);
236
237     QByteArray retval;
238     switch (d->code) {
239         // can only be array, map or struct
240
241     case DBUS_TYPE_ARRAY:
242         Q_ASSERT_X(d->subTypes.size() == 1, "QDBusType::dbusSignature",
243                    "more than one element in array");
244
245         retval += DBUS_TYPE_ARRAY;
246         retval += d->subTypes.at(0).dbusSignature();
247         break;
248
249     case DBUS_TYPE_DICT_ENTRY: {
250         Q_ASSERT_X(d->subTypes.size() == 2, "QDBusType::dbusSignature",
251                    "maps must have exactly two elements");
252
253         QByteArray value = d->subTypes.at(1).dbusSignature();
254         char key = d->subTypes.at(0).dbusType();
255
256         Q_ASSERT(key != DBUS_TYPE_INVALID);
257         Q_ASSERT(!value.isEmpty());
258
259         retval.reserve(value.length() + 3);
260         retval  = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
261         retval += key;
262         retval += value;
263         retval += DBUS_DICT_ENTRY_END_CHAR;
264         break;
265     }
266
267     case DBUS_TYPE_STRUCT:
268         retval = d->subTypes.dbusSignature();
269         retval.prepend(DBUS_STRUCT_BEGIN_CHAR);
270         retval.append(DBUS_STRUCT_END_CHAR);
271         break;
272
273     default:
274         Q_ASSERT_X(false, "QDBusType::dbusSignature", "invalid container type");
275     }
276
277     d->signature = retval;
278     return retval;
279 }
280
281 /*!
282     Returns the QVariant::Type for this entry.
283 */
284 int QDBusType::qvariantType() const
285 {
286     if (d && d->qvariantType != QVariant::Invalid)
287         return d->qvariantType;
288
289     if (!d)
290         return QVariant::Invalid;
291
292     return d->qvariantType = qvariantType(dbusSignature().constData());
293 }
294
295 /*!
296     Returns true if this type is a valid one.
297 */
298 bool QDBusType::isValid() const
299 {
300     return d && d->code != DBUS_TYPE_INVALID;
301 }
302
303 /*!
304     Returns true if this type is a basic one.
305 */
306 bool QDBusType::isBasic() const
307 {
308     return d && dbus_type_is_basic(d->code);
309 }
310
311 /*!
312     Returns true if this type is a container.
313 */
314 bool QDBusType::isContainer() const
315 {
316     return d && dbus_type_is_container(d->code);
317 }
318
319 /*!
320     Returns the subtypes of this type, if this is a container.
321
322     \sa isContainer()
323 */
324 QDBusTypeList QDBusType::subTypes() const
325 {
326     if (d)
327         return d->subTypes;
328     return QDBusTypeList();
329 }
330
331 /*!
332     Returns true if this type is an array.
333
334     \sa isContainer(), arrayElement()
335 */
336 bool QDBusType::isArray() const
337 {
338     return dbusType() == DBUS_TYPE_ARRAY;
339 }
340
341 /*!
342     This is a convenience function that returns the element type of an array.
343     If this object is not an array, it returns an invalid QDBusType.
344
345     \sa isArray()
346 */
347 QDBusType QDBusType::arrayElement() const
348 {
349     if (isArray() && d->subTypes.count() == 1)
350         return d->subTypes.first();
351     return QDBusType();
352 }
353
354 /*!
355     Returns true if this type is a map (i.e., an array of dictionary entries).
356
357     \sa isContainer(), isArray(), arrayElement()
358 */
359 bool QDBusType::isMap() const
360 {
361     return arrayElement().dbusType() == DBUS_TYPE_DICT_ENTRY;
362 }
363
364 /*!
365     If this object is a map, returns the (basic) type that corresponds to the key type.
366     If this object is not a map, returns an invalid QDBusType.
367
368     \sa isMap()
369 */
370 QDBusType QDBusType::mapKey() const
371 {
372     if (isMap())
373         return arrayElement().d->subTypes.first();
374     return QDBusType();
375 }
376
377 /*!
378     If this object is a map, returns the type that corresponds to the value type.
379     If this object is not a map, returns an invalid QDBusType.
380
381     \sa isMap()
382 */
383 QDBusType QDBusType::mapValue() const
384 {
385     if (isMap())
386         return arrayElement().d->subTypes.at(1);
387     return QDBusType();
388 }
389
390 /*!
391     Returns true if this type is the same one as \a other.
392 */
393 bool QDBusType::operator==(const QDBusType& other) const
394 {
395     if (!d && !other.d)
396         return true;
397     if (!d || !other.d)
398         return false;
399     return d->code == other.d->code && d->subTypes == other.d->subTypes;
400 }
401
402 /*!
403     \fn QDBusType::operator!=(const QDBusType &other) const
404     Returns true if the this type and the one given by \a other are different.
405 */
406
407 /*!
408     Converts the DBus type code \a type to QVariant::Type.
409 */
410 int QDBusType::qvariantType(int type)
411 {
412     char c[2] = { type, 0 };
413     return qvariantType(c);
414 }
415
416 /*!
417     Converts the DBus type signature \a signature to QVariant::Type.
418 */
419 int QDBusType::qvariantType(const char* signature)
420 {
421     if (!signature)
422         return QVariant::Invalid;
423
424     // three special cases that don't validate as single:
425     if (qstrlen(signature) == 1) {
426         if (signature[0] == DBUS_TYPE_STRUCT)
427             return QVariant::List;
428         else if (signature[0] == DBUS_TYPE_DICT_ENTRY)
429             return QVariant::Map;
430         else if (signature[0] == DBUS_TYPE_ARRAY)
431             return QVariant::List;
432     }
433
434     // now we can validate
435     if ( !dbus_signature_validate_single(signature, 0) )
436         return QVariant::Invalid;
437
438     switch (signature[0])
439     {
440     case DBUS_TYPE_BOOLEAN:
441         return QVariant::Bool;
442
443     case DBUS_TYPE_BYTE:
444         return QMetaType::UChar;
445
446     case DBUS_TYPE_INT16:
447         return QMetaType::Short;
448
449     case DBUS_TYPE_UINT16:
450         return QMetaType::UShort;
451         
452     case DBUS_TYPE_INT32:
453         return QVariant::Int;
454         
455     case DBUS_TYPE_UINT32:
456         return QVariant::UInt;
457
458     case DBUS_TYPE_INT64:
459         return QVariant::LongLong;
460
461     case DBUS_TYPE_UINT64:
462         return QVariant::ULongLong;
463
464     case DBUS_TYPE_DOUBLE:
465         return QVariant::Double;
466
467     case DBUS_TYPE_STRING:
468     case DBUS_TYPE_OBJECT_PATH:
469     case DBUS_TYPE_SIGNATURE:
470         return QVariant::String;
471
472     case DBUS_STRUCT_BEGIN_CHAR:
473         return QVariant::List;  // change to QDBusStruct in the future
474
475     case DBUS_TYPE_VARIANT:
476         return QDBusTypeHelper<QVariant>::id();
477
478     case DBUS_TYPE_ARRAY:       // special case
479         switch (signature[1]) {
480         case DBUS_TYPE_BOOLEAN:
481             return QDBusTypeHelper<bool>::listId();
482
483         case DBUS_TYPE_BYTE:
484             return QVariant::ByteArray;
485
486         case DBUS_TYPE_INT16:
487             return QDBusTypeHelper<short>::listId();
488
489         case DBUS_TYPE_UINT16:
490             return QDBusTypeHelper<ushort>::listId();
491
492         case DBUS_TYPE_INT32:
493             return QDBusTypeHelper<int>::listId();
494
495         case DBUS_TYPE_UINT32:
496             return QDBusTypeHelper<uint>::listId();
497
498         case DBUS_TYPE_INT64:
499             return QDBusTypeHelper<qlonglong>::listId();
500
501         case DBUS_TYPE_UINT64:
502             return QDBusTypeHelper<qulonglong>::listId();
503
504         case DBUS_TYPE_DOUBLE:
505             return QDBusTypeHelper<double>::listId();
506
507         case DBUS_TYPE_STRING:
508         case DBUS_TYPE_OBJECT_PATH:
509         case DBUS_TYPE_SIGNATURE:
510             return QVariant::StringList;
511
512         case DBUS_TYPE_VARIANT:
513             return QVariant::List;
514
515         case DBUS_DICT_ENTRY_BEGIN_CHAR:
516             return QVariant::Map;
517
518         default:
519             return QVariant::List;
520         }
521     default:
522         return QVariant::Invalid;
523
524     }
525 }
526
527 /*!
528     Converts the QVariant::Type \a t to a DBus type code.
529 */
530 int QDBusType::dbusType(QVariant::Type t)
531 {
532     switch (t)
533     {
534     case QVariant::Bool:
535         return DBUS_TYPE_BOOLEAN;
536
537     case QVariant::Int:
538         return DBUS_TYPE_INT32;
539
540     case QVariant::UInt:
541         return DBUS_TYPE_UINT32;
542
543     case QVariant::LongLong:
544         return DBUS_TYPE_INT64;
545
546     case QVariant::ULongLong:
547         return DBUS_TYPE_UINT64;
548
549     case QVariant::Double:
550         return DBUS_TYPE_DOUBLE;
551
552     // from QMetaType:
553     case QMetaType::Short:
554         return DBUS_TYPE_INT16;
555
556     case QMetaType::UShort:
557         return DBUS_TYPE_UINT16;
558
559     case QMetaType::UChar:
560         return DBUS_TYPE_BYTE;
561
562     case QVariant::String:
563         return DBUS_TYPE_STRING;
564
565     case QVariant::Map:
566         // internal type information has been lost
567         return DBUS_TYPE_DICT_ENTRY;
568
569     case QVariant::List:
570     case QVariant::StringList:
571     case QVariant::ByteArray:
572         // could also be a struct...
573         return DBUS_TYPE_ARRAY;
574
575     case QVariant::UserType:
576         return DBUS_TYPE_INVALID; // invalid
577
578     default:
579         break;                  // avoid compiler warnings
580     }
581
582     if (int(t) == QDBusTypeHelper<QVariant>::id())
583         return DBUS_TYPE_VARIANT;
584
585     return DBUS_TYPE_INVALID;
586 }
587
588 /*!
589     Converts the QVariant::Type \a t to a DBus type signature.
590 */
591 const char* QDBusType::dbusSignature(QVariant::Type t)
592 {
593     switch (t)
594     {
595     case QVariant::Bool:
596         return DBUS_TYPE_BOOLEAN_AS_STRING;
597
598     case QVariant::Int:
599         return DBUS_TYPE_INT32_AS_STRING;
600
601     case QVariant::UInt:
602         return DBUS_TYPE_UINT32_AS_STRING;
603
604     case QMetaType::Short:
605         return DBUS_TYPE_INT16_AS_STRING;
606
607     case QMetaType::UShort:
608         return DBUS_TYPE_UINT16_AS_STRING;
609
610     case QMetaType::UChar:
611         return DBUS_TYPE_BYTE_AS_STRING;
612
613     case QVariant::LongLong:
614         return DBUS_TYPE_INT64_AS_STRING;
615
616     case QVariant::ULongLong:
617         return DBUS_TYPE_UINT64_AS_STRING;
618
619     case QVariant::Double:
620         return DBUS_TYPE_DOUBLE_AS_STRING;
621
622     case QVariant::String:
623         return DBUS_TYPE_STRING_AS_STRING;
624
625     case QVariant::Map:
626         // internal type information has been lost
627         return DBUS_TYPE_ARRAY_AS_STRING
628             DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
629             DBUS_TYPE_STRING_AS_STRING
630             DBUS_TYPE_VARIANT_AS_STRING
631             DBUS_DICT_ENTRY_END_CHAR_AS_STRING; // a{sv}
632
633     case QVariant::StringList:
634         return DBUS_TYPE_ARRAY_AS_STRING
635             DBUS_TYPE_STRING_AS_STRING; // as
636
637     case QVariant::ByteArray:
638         return DBUS_TYPE_ARRAY_AS_STRING
639             DBUS_TYPE_BYTE_AS_STRING; // ay
640
641     case QVariant::List:
642         // not a string list
643         // internal list data has been lost
644         // could also be a struct...
645         return DBUS_TYPE_ARRAY_AS_STRING
646             DBUS_TYPE_VARIANT_AS_STRING; // av
647
648     default:
649         if (int(t) == QDBusTypeHelper<QVariant>::id())
650             return DBUS_TYPE_VARIANT_AS_STRING;
651         if (int(t) == QDBusTypeHelper<bool>::listId())
652             return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BOOLEAN_AS_STRING;
653         if (int(t) == QDBusTypeHelper<short>::listId())
654             return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT16_AS_STRING;
655         if (int(t) == QDBusTypeHelper<ushort>::listId())
656             return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT16_AS_STRING;
657         if (int(t) == QDBusTypeHelper<int>::listId())
658             return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING;
659         if (int(t) == QDBusTypeHelper<uint>::listId())
660             return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING;
661         if (int(t) == QDBusTypeHelper<qlonglong>::listId())
662             return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT64_AS_STRING;
663         if (int(t) == QDBusTypeHelper<qulonglong>::listId())
664             return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT64_AS_STRING;
665         if (int(t) == QDBusTypeHelper<double>::listId())
666             return DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_DOUBLE_AS_STRING;
667
668         return DBUS_TYPE_INVALID_AS_STRING;
669     }
670 }
671
672 /*!
673     \enum QDBusType::VariantListMode
674     Defines how the guessFromVariant() function will behave when the QVariant is of type
675     QVariant::List.
676 */
677
678 /*!
679     Guesses the DBus type from the given \a variant.
680 */
681 QDBusType QDBusType::guessFromVariant(const QVariant& variant, VariantListMode mode)
682 {
683     if (variant.type() == QVariant::List) {
684         // investigate deeper
685         QDBusType t;
686         t.d = new QDBusTypePrivate;
687         const QVariantList list = variant.toList();
688
689         t.d->code = DBUS_TYPE_ARRAY;
690         if (!list.isEmpty()) {
691             // check if all elements have the same type
692             QVariant::Type type = list.first().type();
693             foreach (const QVariant& v, list)
694                 if (type != v.type()) {
695                     // at least one is different
696                     type = QVariant::Invalid;
697                     break;
698                 }
699             
700             if (type != QVariant::Invalid) {
701                 // all are of the same type
702                 t.d->subTypes << guessFromVariant(list.first());
703                 return t;
704             }
705         } else {
706             // an array of "something"
707             t.d->subTypes << QDBusType('v');
708             return t;
709         }
710             
711         // treat it as a struct
712         t.d->code = DBUS_TYPE_STRUCT;
713         foreach (const QVariant& v, list)
714             t.d->subTypes << guessFromVariant(v, mode);
715         
716         return t;
717     }
718     else if (variant.type() == QVariant::Map) {
719         // investigate deeper
720         QDBusType t, t2, t3;
721         t2.d = new QDBusTypePrivate;
722         t2.d->code = DBUS_TYPE_DICT_ENTRY;
723
724         // the key
725         t3.d = new QDBusTypePrivate;
726         t3.d->code = DBUS_TYPE_STRING;
727         t2.d->subTypes << t3;
728
729         const QVariantMap map = variant.toMap();
730         if (!map.isEmpty()) {
731             // check if all elements have the same type
732             QVariantMap::const_iterator it = map.constBegin(),
733                                        end = map.constEnd();
734             QVariant::Type type = it.value().type();
735             for ( ; it != end; ++it)
736                 if (type != it.value().type()) {
737                     // at least one is different
738                     type = QVariant::Invalid;
739                     break;
740                 }
741
742             if (type != QVariant::Invalid)
743                 t2.d->subTypes << guessFromVariant(map.constBegin().value());
744             else {
745                 // multiple types
746                 t3.d->code = DBUS_TYPE_VARIANT;
747                 t2.d->subTypes << t3;
748             }
749         }
750         else {
751             // information lost
752             t3.d->code = DBUS_TYPE_VARIANT;
753             t2.d->subTypes << t3;
754         }
755
756         t.d = new QDBusTypePrivate;
757         t.d->code = DBUS_TYPE_ARRAY;
758         t.d->subTypes << t2;
759         return t;
760     }
761     else
762         return QDBusType( QVariant::Type( variant.userType() ) );
763 }
764
765 /*!
766    \class QDBusTypeList
767    \brief A list of DBus types.
768    \internal
769
770    Represents zero or more DBus types in sequence, such as those used in argument lists
771    or in subtypes of structs and maps.
772 */
773
774 /*!
775    \fn QDBusTypeList::QDBusTypeList()
776
777    Default constructor.
778  */
779
780 /*!
781    \fn QDBusTypeList::QDBusTypeList(const QDBusTypeList& other)
782
783    Copy constructor: copies the type list from \a other.
784 */
785
786 /*!
787    \fn QDBusTypeList::QDBusTypeList(const QList<QDBusType>& other)
788
789    Copy constructor: copies the type list from \a other.
790 */
791
792 /*!
793    Constructs a type list by parsing the given \a signature.
794 */
795 QDBusTypeList::QDBusTypeList(const char* signature)
796 {
797     if (!signature || !*signature)
798         return;                 // empty
799
800     // validate it first
801     if ( !dbus_signature_validate(signature, 0) )
802         return;
803
804     // split it into components
805     DBusSignatureIter iter;
806     dbus_signature_iter_init(&iter, signature);
807
808     do {
809         *this << QDBusType(&iter);
810     } while (dbus_signature_iter_next(&iter));
811 }
812
813 /*!
814     \internal
815     Constructs a type list by parsing the elements on this iterator level.
816 */
817 QDBusTypeList::QDBusTypeList(DBusSignatureIter* iter)
818 {
819     do {
820         QDBusType item(iter);
821         if (!item.isValid()) {
822             clear();
823             return;
824         }
825
826         *this << item;
827     } while (dbus_signature_iter_next(iter));
828 }
829
830 /*!
831     Returns true if this type list can represent the inner components of a map.
832 */
833 bool QDBusTypeList::canBeMap() const
834 {
835     return size() == 2 && at(0).isBasic();
836 }
837
838 /*!
839     Reconstructs the type signature that this type list represents.
840 */
841 QByteArray QDBusTypeList::dbusSignature() const
842 {
843     QByteArray retval;
844     foreach (QDBusType t, *this)
845         retval += t.dbusSignature();
846     return retval;
847 }