2003-05-11 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-message.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message.c  DBusMessage object
3  *
4  * Copyright (C) 2002, 2003  Red Hat Inc.
5  * Copyright (C) 2002, 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 1.2
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
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-internals.h"
26 #include "dbus-marshal.h"
27 #include "dbus-message.h"
28 #include "dbus-message-internal.h"
29 #include "dbus-memory.h"
30 #include "dbus-list.h"
31 #include "dbus-message-builder.h"
32 #include <string.h>
33
34 /**
35  * @defgroup DBusMessageInternals DBusMessage implementation details
36  * @ingroup DBusInternals
37  * @brief DBusMessage private implementation details.
38  *
39  * The guts of DBusMessage and its methods.
40  *
41  * @{
42  */
43
44 enum
45 {
46   FIELD_HEADER_LENGTH,
47   FIELD_BODY_LENGTH,
48   FIELD_CLIENT_SERIAL,
49   FIELD_NAME,
50   FIELD_SERVICE,
51   FIELD_SENDER,
52   FIELD_REPLY_SERIAL,
53
54   FIELD_LAST
55 };
56
57 static dbus_bool_t field_is_named[FIELD_LAST] =
58 {
59   FALSE, /* FIELD_HEADER_LENGTH */
60   FALSE, /* FIELD_BODY_LENGTH */
61   FALSE, /* FIELD_CLIENT_SERIAL */
62   TRUE,  /* FIELD_NAME */
63   TRUE,  /* FIELD_SERVICE */
64   TRUE,  /* FIELD_SENDER */
65   TRUE   /* FIELD_REPLY_SERIAL */
66 };
67
68 typedef struct
69 {
70   int offset; /**< Offset to start of field (location of name of field
71                * for named fields)
72                */
73 } HeaderField;
74
75 /**
76  * @brief Internals of DBusMessage
77  * 
78  * Object representing a message received from or to be sent to
79  * another application. This is an opaque object, all members
80  * are private.
81  */
82 struct DBusMessage
83 {
84   volatile dbus_atomic_t refcount; /**< Reference count */
85
86   DBusString header; /**< Header network data, stored
87                       * separately from body so we can
88                       * independently realloc it.
89                       */
90
91   HeaderField header_fields[FIELD_LAST]; /**< Track the location
92                                            * of each field in "header"
93                                            */
94
95   dbus_uint32_t client_serial; /**< Cached client serial value for speed */
96   dbus_uint32_t reply_serial;  /**< Cached reply serial value for speed */
97   
98   int header_padding; /**< bytes of alignment in header */
99   
100   DBusString body;   /**< Body network data. */
101
102   char byte_order; /**< Message byte order. */
103
104   DBusList *size_counters;   /**< 0-N DBusCounter used to track message size. */
105   long size_counter_delta;   /**< Size we incremented the size counters by.   */
106
107   dbus_uint32_t changed_stamp; /**< Incremented when iterators are invalidated. */
108   
109   unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
110 };
111
112 enum {
113   DBUS_MESSAGE_ITER_TYPE_MESSAGE,
114   DBUS_MESSAGE_ITER_TYPE_ARRAY,
115   DBUS_MESSAGE_ITER_TYPE_DICT
116 };
117
118 /** typedef for internals of message iterator */
119 typedef struct DBusMessageRealIter DBusMessageRealIter;
120
121 /**
122  * @brief Internals of DBusMessageIter
123  * 
124  * Object representing a position in a message. All fields are internal.
125  */
126 struct DBusMessageRealIter
127 {
128   DBusMessageRealIter *parent_iter; /**< parent iter, or NULL */
129   DBusMessage *message; /**< Message used */
130   dbus_uint32_t changed_stamp; /**< stamp to detect invalid iters */
131   
132   /* This is an int instead of an enum to get a guaranteed size for the dummy: */
133   int type; /**< type of iter */
134   
135   int pos; /**< Current position in the string */
136   int end; /**< position right after the container */
137   int container_start; /**< offset of the start of the container */
138   int container_length_pos; /**< offset of the length of the container */
139   
140   int wrote_dict_key; /**< whether we wrote the dict key for the current dict element */
141
142   int array_type_pos; /**< pointer to the position of the array element type */
143   int array_type_done; /**< TRUE if the array type is fully finished */
144 };
145
146 /**
147  * Gets the data to be sent over the network for this message.
148  * The header and then the body should be written out.
149  * This function is guaranteed to always return the same
150  * data once a message is locked (with _dbus_message_lock()).
151  *
152  * @param message the message.
153  * @param header return location for message header data.
154  * @param body return location for message body data.
155  */
156 void
157 _dbus_message_get_network_data (DBusMessage          *message,
158                                 const DBusString    **header,
159                                 const DBusString    **body)
160 {
161   _dbus_assert (message->locked);
162   
163   *header = &message->header;
164   *body = &message->body;
165 }
166
167 static void
168 clear_header_padding (DBusMessage *message)
169 {
170   _dbus_string_shorten (&message->header,
171                         message->header_padding);
172   message->header_padding = 0;
173 }              
174
175 static dbus_bool_t
176 append_header_padding (DBusMessage *message)
177 {
178   int old_len;
179   old_len = _dbus_string_get_length (&message->header);
180   if (!_dbus_string_align_length (&message->header, 8))
181     return FALSE;
182
183   message->header_padding = _dbus_string_get_length (&message->header) - old_len;
184
185   return TRUE;
186 }
187
188 static void
189 adjust_field_offsets (DBusMessage *message,
190                       int          offsets_after,
191                       int          delta)
192 {
193   int i;
194
195   if (delta == 0)
196     return;
197   
198   i = 0;
199   while (i < FIELD_LAST)
200     {
201       if (message->header_fields[i].offset > offsets_after)
202         message->header_fields[i].offset += delta;
203
204       ++i;
205     }
206 }
207
208 #ifdef DBUS_BUILD_TESTS
209 /* tests-only until it's actually used */
210 static dbus_int32_t
211 get_int_field (DBusMessage *message,
212                int          field)
213 {
214   int offset;
215
216   _dbus_assert (field < FIELD_LAST);
217   
218   offset = message->header_fields[field].offset;
219   
220   if (offset < 0)
221     return -1; /* useless if -1 is a valid value of course */
222   
223   return _dbus_demarshal_int32 (&message->header,
224                                 message->byte_order,
225                                 offset,
226                                 NULL);
227 }
228 #endif
229
230 static dbus_uint32_t
231 get_uint_field (DBusMessage *message,
232                 int          field)
233 {
234   int offset;
235   
236   _dbus_assert (field < FIELD_LAST);
237   
238   offset = message->header_fields[field].offset;
239   
240   if (offset < 0)
241     return -1; /* useless if -1 is a valid value of course */
242   
243   return _dbus_demarshal_uint32 (&message->header,
244                                  message->byte_order,
245                                  offset,
246                                  NULL);
247 }
248
249 static const char*
250 get_string_field (DBusMessage *message,
251                   int          field,
252                   int         *len)
253 {
254   int offset;
255   const char *data;
256
257   offset = message->header_fields[field].offset;
258
259   _dbus_assert (field < FIELD_LAST);
260   
261   if (offset < 0)
262     return NULL;
263
264   /* offset points to string length, string data follows it */
265   /* FIXME _dbus_demarshal_const_string() that returned
266    * a reference to the string plus its len might be nice.
267    */
268   
269   if (len)
270     *len = _dbus_demarshal_uint32 (&message->header,
271                                    message->byte_order,
272                                    offset,
273                                    NULL);
274
275   data = _dbus_string_get_const_data (&message->header);
276   
277   return data + (offset + 4); 
278 }
279
280 #ifdef DBUS_BUILD_TESTS
281 static dbus_bool_t
282 append_int_field (DBusMessage *message,
283                   int          field,
284                   const char  *name,
285                   int          value)
286 {
287   int orig_len;
288
289   _dbus_assert (!message->locked);
290
291   clear_header_padding (message);
292   
293   orig_len = _dbus_string_get_length (&message->header);
294   
295   if (!_dbus_string_align_length (&message->header, 4))
296     goto failed;  
297   
298   if (!_dbus_string_append_len (&message->header, name, 4))
299     goto failed;
300
301   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32))
302     goto failed;
303
304   if (!_dbus_string_align_length (&message->header, 4))
305     goto failed;
306   
307   message->header_fields[FIELD_REPLY_SERIAL].offset =
308     _dbus_string_get_length (&message->header);
309   
310   if (!_dbus_marshal_int32 (&message->header, message->byte_order,
311                             value))
312     goto failed;
313
314   if (!append_header_padding (message))
315     goto failed;
316   
317   return TRUE;
318   
319  failed:
320   message->header_fields[field].offset = -1;
321   _dbus_string_set_length (&message->header, orig_len);
322
323   /* this must succeed because it was allocated on function entry and
324    * DBusString doesn't ever realloc smaller
325    */
326   if (!append_header_padding (message))
327     _dbus_assert_not_reached ("failed to reappend header padding");
328   return FALSE;
329 }
330 #endif
331
332 static dbus_bool_t
333 append_uint_field (DBusMessage *message,
334                    int          field,
335                    const char  *name,
336                    int          value)
337 {
338   int orig_len;
339
340   _dbus_assert (!message->locked);
341
342   clear_header_padding (message);
343   
344   orig_len = _dbus_string_get_length (&message->header);
345   
346   if (!_dbus_string_align_length (&message->header, 4))
347     goto failed;  
348   
349   if (!_dbus_string_append_len (&message->header, name, 4))
350     goto failed;
351
352   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_UINT32))
353     goto failed;
354
355   if (!_dbus_string_align_length (&message->header, 4))
356     goto failed;
357   
358   message->header_fields[FIELD_REPLY_SERIAL].offset =
359     _dbus_string_get_length (&message->header);
360   
361   if (!_dbus_marshal_uint32 (&message->header, message->byte_order,
362                              value))
363     goto failed;
364
365   if (!append_header_padding (message))
366     goto failed;
367   
368   return TRUE;
369   
370  failed:
371   message->header_fields[field].offset = -1;
372   _dbus_string_set_length (&message->header, orig_len);
373
374   /* this must succeed because it was allocated on function entry and
375    * DBusString doesn't ever realloc smaller
376    */
377   if (!append_header_padding (message))
378     _dbus_assert_not_reached ("failed to reappend header padding");
379   return FALSE;
380 }
381
382 static dbus_bool_t
383 append_string_field (DBusMessage *message,
384                      int          field,
385                      const char  *name,
386                      const char  *value)
387 {
388   int orig_len;
389
390   _dbus_assert (!message->locked);
391
392   clear_header_padding (message);
393   
394   orig_len = _dbus_string_get_length (&message->header);
395
396   if (!_dbus_string_align_length (&message->header, 4))
397     goto failed;
398   
399   if (!_dbus_string_append_len (&message->header, name, 4))
400     goto failed;
401   
402   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING))
403     goto failed;
404
405   if (!_dbus_string_align_length (&message->header, 4))
406     goto failed;
407   
408   message->header_fields[field].offset =
409     _dbus_string_get_length (&message->header);
410   
411   if (!_dbus_marshal_string (&message->header, message->byte_order,
412                              value))
413     goto failed;
414
415   if (!append_header_padding (message))
416     goto failed;
417   
418   return TRUE;
419   
420  failed:
421   message->header_fields[field].offset = -1;
422   _dbus_string_set_length (&message->header, orig_len);
423
424   /* this must succeed because it was allocated on function entry and
425    * DBusString doesn't ever realloc smaller
426    */
427   if (!append_header_padding (message))
428     _dbus_assert_not_reached ("failed to reappend header padding");
429   
430   return FALSE;
431 }
432
433 #ifdef DBUS_BUILD_TESTS
434 /* This isn't used, but building it when tests are enabled just to
435  * keep it compiling if we need it in future
436  */
437 static void
438 delete_int_or_uint_field (DBusMessage *message,
439                           int          field)
440 {
441   int offset = message->header_fields[field].offset;
442
443   _dbus_assert (!message->locked);
444   _dbus_assert (field_is_named[field]);
445   
446   if (offset < 0)
447     return;  
448
449   clear_header_padding (message);
450   
451   /* The field typecode and name take up 8 bytes */
452   _dbus_string_delete (&message->header,
453                        offset - 8,
454                        12);
455
456   message->header_fields[field].offset = -1;
457   
458   adjust_field_offsets (message,
459                         offset - 8,
460                         - 12);
461
462   append_header_padding (message);
463 }
464 #endif
465
466 static void
467 delete_string_field (DBusMessage *message,
468                      int          field)
469 {
470   int offset = message->header_fields[field].offset;
471   int len;
472   int delete_len;
473   
474   _dbus_assert (!message->locked);
475   _dbus_assert (field_is_named[field]);
476   
477   if (offset < 0)
478     return;
479
480   clear_header_padding (message);
481   
482   get_string_field (message, field, &len);
483   
484   /* The field typecode and name take up 8 bytes, and the nul
485    * termination is 1 bytes, string length integer is 4 bytes
486    */
487   delete_len = 8 + 4 + 1 + len;
488   
489   _dbus_string_delete (&message->header,
490                        offset - 8,
491                        delete_len);
492
493   message->header_fields[field].offset = -1;
494   
495   adjust_field_offsets (message,
496                         offset - 8,
497                         - delete_len);
498
499   append_header_padding (message);
500 }
501
502 #ifdef DBUS_BUILD_TESTS
503 static dbus_bool_t
504 set_int_field (DBusMessage *message,
505                int          field,
506                int          value)
507 {
508   int offset = message->header_fields[field].offset;
509
510   _dbus_assert (!message->locked);
511   
512   if (offset < 0)
513     {
514       /* need to append the field */
515
516       switch (field)
517         {
518         default:
519           _dbus_assert_not_reached ("appending an int field we don't support appending");
520           return FALSE;
521         }
522     }
523   else
524     {
525       _dbus_marshal_set_int32 (&message->header,
526                                message->byte_order,
527                                offset, value);
528
529       return TRUE;
530     }
531 }
532 #endif
533
534 static dbus_bool_t
535 set_uint_field (DBusMessage  *message,
536                 int           field,
537                 dbus_uint32_t value)
538 {
539   int offset = message->header_fields[field].offset;
540
541   _dbus_assert (!message->locked);
542   
543   if (offset < 0)
544     {
545       /* need to append the field */
546
547       switch (field)
548         {
549         case FIELD_REPLY_SERIAL:
550           return append_uint_field (message, field,
551                                     DBUS_HEADER_FIELD_REPLY,
552                                     value);
553         default:
554           _dbus_assert_not_reached ("appending a uint field we don't support appending");
555           return FALSE;
556         }
557     }
558   else
559     {
560       _dbus_marshal_set_uint32 (&message->header,
561                                 message->byte_order,
562                                 offset, value);
563
564       return TRUE;
565     }
566 }
567
568 static dbus_bool_t
569 set_string_field (DBusMessage *message,
570                   int          field,
571                   const char  *value)
572 {
573   int offset = message->header_fields[field].offset;
574
575   _dbus_assert (!message->locked);
576   _dbus_assert (value != NULL);
577   
578   if (offset < 0)
579     {      
580       /* need to append the field */
581
582       switch (field)
583         {
584         case FIELD_SENDER:
585           return append_string_field (message, field,
586                                       DBUS_HEADER_FIELD_SENDER,
587                                       value);
588         default:
589           _dbus_assert_not_reached ("appending a string field we don't support appending");
590           return FALSE;
591         }
592     }
593   else
594     {
595       DBusString v;
596       int old_len;
597       int new_len;
598       int len;
599       
600       clear_header_padding (message);
601       
602       old_len = _dbus_string_get_length (&message->header);
603
604       len = strlen (value);
605       
606       _dbus_string_init_const_len (&v, value,
607                                    len + 1); /* include nul */
608       if (!_dbus_marshal_set_string (&message->header,
609                                      message->byte_order,
610                                      offset, &v,
611                                      len))
612         goto failed;
613       
614       new_len = _dbus_string_get_length (&message->header);
615
616       adjust_field_offsets (message,
617                             offset,
618                             new_len - old_len);
619
620       if (!append_header_padding (message))
621         goto failed;
622       
623       return TRUE;
624
625     failed:
626       /* this must succeed because it was allocated on function entry and
627        * DBusString doesn't ever realloc smaller
628        */
629       if (!append_header_padding (message))
630         _dbus_assert_not_reached ("failed to reappend header padding");
631
632       return FALSE;
633     }
634 }
635
636 /**
637  * Sets the serial number of a message. 
638  * This can only be done once on a message.
639  * 
640  * @param message the message
641  * @param serial the serial
642  */
643 void
644 _dbus_message_set_serial (DBusMessage  *message,
645                           dbus_int32_t  serial)
646 {
647   _dbus_assert (!message->locked);
648   _dbus_assert (dbus_message_get_serial (message) == 0);
649   
650   set_uint_field (message, FIELD_CLIENT_SERIAL,
651                   serial);
652   message->client_serial = serial;
653 }
654
655 /**
656  * Sets the reply serial of a message (the client serial
657  * of the message this is a reply to).
658  *
659  * @param message the message
660  * @param reply_serial the client serial
661  * @returns #FALSE if not enough memory
662  */
663 dbus_bool_t
664 dbus_message_set_reply_serial (DBusMessage   *message,
665                                dbus_uint32_t  reply_serial)
666 {
667   _dbus_assert (!message->locked);
668
669   if (set_uint_field (message, FIELD_REPLY_SERIAL,
670                       reply_serial))
671     {
672       message->reply_serial = reply_serial;
673       return TRUE;
674     }
675   else
676     return FALSE;
677 }
678
679 /**
680  * Returns the serial of a message or -1 if none has been specified.
681  * The message's serial number is provided by the application sending
682  * the message and is used to identify replies to this message.
683  *
684  * @param message the message
685  * @returns the client serial
686  */
687 dbus_uint32_t
688 dbus_message_get_serial (DBusMessage *message)
689 {
690   return message->client_serial;
691 }
692
693 /**
694  * Returns the serial that the message is
695  * a reply to or 0 if none.
696  *
697  * @param message the message
698  * @returns the reply serial
699  */
700 dbus_uint32_t
701 dbus_message_get_reply_serial  (DBusMessage *message)
702 {
703   return message->reply_serial;
704 }
705
706 /**
707  * Adds a counter to be incremented immediately with the
708  * size of this message, and decremented by the size
709  * of this message when this message if finalized.
710  * The link contains a counter with its refcount already
711  * incremented, but the counter itself not incremented.
712  * Ownership of link and counter refcount is passed to
713  * the message.
714  *
715  * @param message the message
716  * @param link link with counter as data
717  */
718 void
719 _dbus_message_add_size_counter_link (DBusMessage  *message,
720                                      DBusList     *link)
721 {
722   /* right now we don't recompute the delta when message
723    * size changes, and that's OK for current purposes
724    * I think, but could be important to change later.
725    * Do recompute it whenever there are no outstanding counters,
726    * since it's basically free.
727    */
728   if (message->size_counters == NULL)
729     {
730       message->size_counter_delta =
731         _dbus_string_get_length (&message->header) +
732         _dbus_string_get_length (&message->body);
733       
734 #if 0
735       _dbus_verbose ("message has size %ld\n",
736                      message->size_counter_delta);
737 #endif
738     }
739   
740   _dbus_list_append_link (&message->size_counters, link);
741   
742   _dbus_counter_adjust (link->data, message->size_counter_delta);
743 }
744
745 /**
746  * Adds a counter to be incremented immediately with the
747  * size of this message, and decremented by the size
748  * of this message when this message if finalized.
749  *
750  * @param message the message
751  * @param counter the counter
752  * @returns #FALSE if no memory
753  */
754 dbus_bool_t
755 _dbus_message_add_size_counter (DBusMessage *message,
756                                 DBusCounter *counter)
757 {
758   DBusList *link;
759
760   link = _dbus_list_alloc_link (counter);
761   if (link == NULL)
762     return FALSE;
763
764   _dbus_counter_ref (counter);
765   _dbus_message_add_size_counter_link (message, link);
766
767   return TRUE;
768 }
769
770 /**
771  * Removes a counter tracking the size of this message, and decrements
772  * the counter by the size of this message.
773  *
774  * @param message the message
775  * @param counter the counter
776  */
777 void
778 _dbus_message_remove_size_counter (DBusMessage  *message,
779                                    DBusCounter  *counter)
780 {
781   if (!_dbus_list_remove_last (&message->size_counters,
782                                counter))
783     _dbus_assert_not_reached ("Removed a message size counter that was not added");
784
785   _dbus_counter_adjust (counter, message->size_counter_delta);
786
787   _dbus_counter_unref (counter);
788 }
789
790 static dbus_bool_t
791 dbus_message_create_header (DBusMessage *message,
792                             const char  *name,
793                             const char  *service)
794 {
795   unsigned int flags;
796   
797   if (!_dbus_string_append_byte (&message->header, message->byte_order))
798     return FALSE;
799
800   flags = 0;
801   if (!_dbus_string_append_byte (&message->header, flags))
802     return FALSE;
803
804   if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION))
805     return FALSE;
806
807   if (!_dbus_string_append_byte (&message->header, 0))
808     return FALSE;
809
810   message->header_fields[FIELD_HEADER_LENGTH].offset = 4;
811   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
812     return FALSE;
813
814   message->header_fields[FIELD_BODY_LENGTH].offset = 8;
815   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
816     return FALSE;
817
818   message->header_fields[FIELD_CLIENT_SERIAL].offset = 12;
819   if (!_dbus_marshal_int32 (&message->header, message->byte_order, -1))
820     return FALSE;
821   
822   /* Marshal message service */
823   if (service != NULL)
824     {
825       if (!append_string_field (message,
826                                 FIELD_SERVICE,
827                                 DBUS_HEADER_FIELD_SERVICE,
828                                 service))
829         return FALSE;
830     }
831
832   _dbus_assert (name != NULL);
833   if (!append_string_field (message,
834                             FIELD_NAME,
835                             DBUS_HEADER_FIELD_NAME,
836                             name))
837     return FALSE;
838   
839   return TRUE;
840 }
841
842 /**
843  * Locks a message. Allows checking that applications don't keep a
844  * reference to a message in the outgoing queue and change it
845  * underneath us. Messages are locked when they enter the outgoing
846  * queue (dbus_connection_send_message()), and the library complains
847  * if the message is modified while locked.
848  *
849  * @param message the message to lock.
850  */
851 void
852 _dbus_message_lock (DBusMessage  *message)
853 {
854   if (!message->locked)
855     {
856       /* Fill in our lengths */
857       set_uint_field (message,
858                       FIELD_HEADER_LENGTH,
859                       _dbus_string_get_length (&message->header));
860
861       set_uint_field (message,
862                       FIELD_BODY_LENGTH,
863                       _dbus_string_get_length (&message->body));
864
865       message->locked = TRUE;
866     }
867 }
868
869 /** @} */
870
871 /**
872  * @defgroup DBusMessage DBusMessage
873  * @ingroup  DBus
874  * @brief Message to be sent or received over a DBusConnection.
875  *
876  * A DBusMessage is the most basic unit of communication over a
877  * DBusConnection. A DBusConnection represents a stream of messages
878  * received from a remote application, and a stream of messages
879  * sent to a remote application.
880  *
881  * @{
882  */
883
884 /**
885  * @typedef DBusMessage
886  *
887  * Opaque data type representing a message received from or to be
888  * sent to another application.
889  */
890
891 static DBusMessage*
892 dbus_message_new_empty_header (void)
893 {
894   DBusMessage *message;
895   int i;
896   
897   message = dbus_new0 (DBusMessage, 1);
898   if (message == NULL)
899     return NULL;
900   
901   message->refcount = 1;
902   message->byte_order = DBUS_COMPILER_BYTE_ORDER;
903   message->client_serial = 0;
904   message->reply_serial = 0;
905   
906   i = 0;
907   while (i < FIELD_LAST)
908     {
909       message->header_fields[i].offset = -1;
910       ++i;
911     }
912   
913   if (!_dbus_string_init (&message->header))
914     {
915       dbus_free (message);
916       return NULL;
917     }
918   
919   if (!_dbus_string_init (&message->body))
920     {
921       _dbus_string_free (&message->header);
922       dbus_free (message);
923       return NULL;
924     }
925   
926   return message;
927 }
928
929
930 /**
931  * Constructs a new message. Returns #NULL if memory can't be
932  * allocated for the message. The service may be #NULL in which case
933  * no service is set; this is appropriate when using D-BUS in a
934  * peer-to-peer context (no message bus).
935  *
936  * @todo reverse the arguments, first 'name' then 'service'
937  * as 'name' is more fundamental
938  *
939  * @param name name of the message
940  * @param destination_service service that the message should be sent to or #NULL
941  * @returns a new DBusMessage, free with dbus_message_unref()
942  * @see dbus_message_unref()
943  */
944 DBusMessage*
945 dbus_message_new (const char *name,
946                   const char *destination_service)                
947 {
948   DBusMessage *message;
949
950   _dbus_return_val_if_fail (name != NULL, NULL);
951   
952   message = dbus_message_new_empty_header ();
953   if (message == NULL)
954     return NULL;
955   
956   if (!dbus_message_create_header (message, name, destination_service))
957     {
958       dbus_message_unref (message);
959       return NULL;
960     }
961   
962   return message;
963 }
964
965 /**
966  * Constructs a message that is a reply to some other
967  * message. Returns #NULL if memory can't be allocated
968  * for the message.
969  *
970  * @param original_message the message which the created
971  * message is a reply to.
972  * @returns a new DBusMessage, free with dbus_message_unref()
973  * @see dbus_message_new(), dbus_message_unref()
974  */ 
975 DBusMessage*
976 dbus_message_new_reply (DBusMessage *original_message)
977 {
978   DBusMessage *message;
979   const char *sender, *name;
980
981   _dbus_return_val_if_fail (original_message != NULL, NULL);
982   
983   sender = get_string_field (original_message,
984                              FIELD_SENDER, NULL);
985   name = get_string_field (original_message,
986                            FIELD_NAME, NULL);
987
988   /* sender is allowed to be null here in peer-to-peer case */
989   
990   message = dbus_message_new (name, sender);
991   
992   if (message == NULL)
993     return NULL;
994
995   if (!dbus_message_set_reply_serial (message,
996                                       dbus_message_get_serial (original_message)))
997     {
998       dbus_message_unref (message);
999       return NULL;
1000     }
1001
1002   return message;
1003 }
1004
1005 /**
1006  * Creates a new message that is an error reply to a certain message.
1007  *
1008  * @param original_message the original message
1009  * @param error_name the error name
1010  * @param error_message the error message string or #NULL for none
1011  * @returns a new error message
1012  */
1013 DBusMessage*
1014 dbus_message_new_error_reply (DBusMessage *original_message,
1015                               const char  *error_name,
1016                               const char  *error_message)
1017 {
1018   DBusMessage *message;
1019   const char *sender;
1020   DBusMessageIter iter;
1021
1022   _dbus_return_val_if_fail (original_message != NULL, NULL);
1023   _dbus_return_val_if_fail (error_name != NULL, NULL);
1024   
1025   sender = get_string_field (original_message,
1026                              FIELD_SENDER, NULL);
1027
1028   /* sender may be NULL for non-message-bus case or
1029    * when the message bus is dealing with an unregistered
1030    * connection.
1031    */
1032   
1033   message = dbus_message_new (error_name, sender);
1034   
1035   if (message == NULL)
1036     return NULL;
1037
1038   if (!dbus_message_set_reply_serial (message,
1039                                       dbus_message_get_serial (original_message)))
1040     {
1041       dbus_message_unref (message);
1042       return NULL;
1043     }
1044
1045   if (error_message != NULL)
1046     {
1047       dbus_message_append_iter_init (message, &iter);
1048       if (!dbus_message_iter_append_string (&iter, error_message))
1049         {
1050           dbus_message_unref (message);
1051           return NULL;
1052         }
1053     }
1054
1055   dbus_message_set_is_error (message, TRUE);
1056   
1057   return message;
1058 }
1059
1060 /**
1061  * Creates a new message that is an exact replica of the message
1062  * specified, except that its refcount is set to 1.
1063  *
1064  * @param message the message.
1065  * @returns the new message.
1066  */
1067 DBusMessage *
1068 dbus_message_copy (const DBusMessage *message)
1069 {
1070   DBusMessage *retval;
1071   int i;
1072
1073   _dbus_return_val_if_fail (message != NULL, NULL);
1074   
1075   retval = dbus_new0 (DBusMessage, 1);
1076   if (retval == NULL)
1077     return NULL;
1078   
1079   retval->refcount = 1;
1080   retval->byte_order = message->byte_order;
1081   retval->client_serial = message->client_serial;
1082   retval->reply_serial = message->reply_serial;
1083   retval->header_padding = message->header_padding;
1084   retval->locked = FALSE;
1085   
1086   if (!_dbus_string_init (&retval->header))
1087     {
1088       dbus_free (retval);
1089       return NULL;
1090     }
1091   
1092   if (!_dbus_string_init (&retval->body))
1093     {
1094       _dbus_string_free (&retval->header);
1095       dbus_free (retval);
1096       return NULL;
1097     }
1098
1099   if (!_dbus_string_copy (&message->header, 0,
1100                           &retval->header, 0))
1101     {
1102       _dbus_string_free (&retval->header);
1103       _dbus_string_free (&retval->body);
1104       dbus_free (retval);
1105
1106       return NULL;
1107     }
1108
1109   if (!_dbus_string_copy (&message->body, 0,
1110                           &retval->body, 0))
1111     {
1112       _dbus_string_free (&retval->header);
1113       _dbus_string_free (&retval->body);
1114       dbus_free (retval);
1115
1116       return NULL;
1117     }
1118
1119   for (i = 0; i < FIELD_LAST; i++)
1120     {
1121       retval->header_fields[i].offset = message->header_fields[i].offset;
1122     }
1123   
1124   return retval;
1125 }
1126
1127
1128 /**
1129  * Increments the reference count of a DBusMessage.
1130  *
1131  * @param message The message
1132  * @see dbus_message_unref
1133  */
1134 void
1135 dbus_message_ref (DBusMessage *message)
1136 {
1137   volatile dbus_atomic_t refcount;
1138
1139   _dbus_return_if_fail (message != NULL);
1140   
1141   refcount = _dbus_atomic_inc (&message->refcount);
1142   _dbus_assert (refcount > 1);
1143 }
1144
1145 static void
1146 free_size_counter (void *element,
1147                    void *data)
1148 {
1149   DBusCounter *counter = element;
1150   DBusMessage *message = data;
1151   
1152   _dbus_counter_adjust (counter, - message->size_counter_delta);
1153
1154   _dbus_counter_unref (counter);
1155 }
1156
1157 /**
1158  * Decrements the reference count of a DBusMessage.
1159  *
1160  * @param message The message
1161  * @see dbus_message_ref
1162  */
1163 void
1164 dbus_message_unref (DBusMessage *message)
1165 {
1166   volatile dbus_atomic_t refcount;
1167
1168   _dbus_return_if_fail (message != NULL);
1169   
1170   refcount = _dbus_atomic_dec (&message->refcount);
1171   
1172   _dbus_assert (refcount >= 0);
1173
1174   if (refcount == 0)
1175     {
1176       _dbus_list_foreach (&message->size_counters,
1177                           free_size_counter, message);
1178       _dbus_list_clear (&message->size_counters);
1179       
1180       _dbus_string_free (&message->header);
1181       _dbus_string_free (&message->body);
1182       
1183       dbus_free (message);
1184     }
1185 }
1186
1187 /**
1188  * Gets the name of a message.
1189  *
1190  * @param message the message
1191  * @returns the message name (should not be freed)
1192  */
1193 const char*
1194 dbus_message_get_name (DBusMessage *message)
1195 {
1196   _dbus_return_val_if_fail (message != NULL, NULL);
1197   
1198   return get_string_field (message, FIELD_NAME, NULL);
1199 }
1200
1201 /**
1202  * Gets the destination service of a message.
1203  * 
1204  * @param message the message
1205  * @returns the message destination service (should not be freed)
1206  */
1207 const char*
1208 dbus_message_get_destination (DBusMessage *message)
1209 {
1210   _dbus_return_val_if_fail (message != NULL, NULL);
1211   
1212   return get_string_field (message, FIELD_SERVICE, NULL);
1213 }
1214
1215 /**
1216  * Appends fields to a message given a variable argument list. The
1217  * variable argument list should contain the type of the argument
1218  * followed by the value to add.  Array values are specified by an int
1219  * typecode followed by a pointer to the array followed by an int
1220  * giving the length of the array.  The argument list must be
1221  * terminated with DBUS_TYPE_INVALID.
1222  *
1223  * This function doesn't support dicts or non-fundamental arrays.
1224  *
1225  * This function supports #DBUS_TYPE_INT64 and #DBUS_TYPE_UINT64
1226  * only if #DBUS_HAVE_INT64 is defined.
1227  *
1228  * @param message the message
1229  * @param first_arg_type type of the first argument
1230  * @param ... value of first argument, list of additional type-value pairs
1231  * @returns #TRUE on success
1232  */
1233 dbus_bool_t
1234 dbus_message_append_args (DBusMessage *message,
1235                           int first_arg_type,
1236                           ...)
1237 {
1238   dbus_bool_t retval;
1239   va_list var_args;
1240
1241   _dbus_return_val_if_fail (message != NULL, FALSE);
1242   
1243   va_start (var_args, first_arg_type);
1244   retval = dbus_message_append_args_valist (message,
1245                                             first_arg_type,
1246                                             var_args);
1247   va_end (var_args);
1248
1249   return retval;
1250 }
1251
1252 /**
1253  * This function takes a va_list for use by language bindings.
1254  * It's otherwise the same as dbus_message_append_args().
1255  *
1256  * @todo: Shouldn't this function clean up the changes to the message
1257  *        on failures? (Yes)
1258   
1259  * @see dbus_message_append_args.  
1260  * @param message the message
1261  * @param first_arg_type type of first argument
1262  * @param var_args value of first argument, then list of type/value pairs
1263  * @returns #TRUE on success
1264  */
1265 dbus_bool_t
1266 dbus_message_append_args_valist (DBusMessage *message,
1267                                  int          first_arg_type,
1268                                  va_list      var_args)
1269 {
1270   int type, old_len;
1271   DBusMessageIter iter;
1272
1273   _dbus_return_val_if_fail (message != NULL, FALSE);
1274   
1275   old_len = _dbus_string_get_length (&message->body);
1276   
1277   type = first_arg_type;
1278
1279   dbus_message_append_iter_init (message, &iter);
1280   
1281   while (type != 0)
1282     {
1283       switch (type)
1284         {
1285         case DBUS_TYPE_NIL:
1286           if (!dbus_message_iter_append_nil (&iter))
1287             goto errorout;
1288           break;
1289         case DBUS_TYPE_BOOLEAN:
1290           if (!dbus_message_iter_append_boolean (&iter, va_arg (var_args, dbus_bool_t)))
1291             goto errorout;
1292           break;
1293         case DBUS_TYPE_INT32:
1294           if (!dbus_message_iter_append_int32 (&iter, va_arg (var_args, dbus_int32_t)))
1295             goto errorout;
1296           break;
1297         case DBUS_TYPE_UINT32:
1298           if (!dbus_message_iter_append_uint32 (&iter, va_arg (var_args, dbus_uint32_t)))
1299             goto errorout;          
1300           break;
1301 #ifdef DBUS_HAVE_INT64
1302         case DBUS_TYPE_INT64:
1303           if (!dbus_message_iter_append_int64 (&iter, va_arg (var_args, dbus_int64_t)))
1304             goto errorout;
1305           break;
1306         case DBUS_TYPE_UINT64:
1307           if (!dbus_message_iter_append_uint64 (&iter, va_arg (var_args, dbus_uint64_t)))
1308             goto errorout;          
1309           break;
1310 #endif /* DBUS_HAVE_INT64 */
1311         case DBUS_TYPE_DOUBLE:
1312           if (!dbus_message_iter_append_double (&iter, va_arg (var_args, double)))
1313             goto errorout;
1314           break;
1315         case DBUS_TYPE_STRING:
1316           if (!dbus_message_iter_append_string (&iter, va_arg (var_args, const char *)))
1317             goto errorout;
1318           break;
1319         case DBUS_TYPE_NAMED:
1320           {
1321             const char *name;
1322             unsigned char *data;
1323             int len;
1324  
1325             name = va_arg (var_args, const char *);
1326             data = va_arg (var_args, unsigned char *);
1327             len = va_arg (var_args, int);
1328
1329             if (!dbus_message_iter_append_named (&iter, name, data, len))
1330               goto errorout;
1331             break;
1332           }
1333         case DBUS_TYPE_ARRAY:
1334           {
1335             void *data;
1336             int len, type;
1337  
1338             type = va_arg (var_args, int);
1339             data = va_arg (var_args, void *);
1340             len = va_arg (var_args, int);
1341
1342             switch (type)
1343               {
1344               case DBUS_TYPE_BYTE:
1345                 if (!dbus_message_iter_append_byte_array (&iter, (unsigned char *)data, len))
1346                   goto errorout;
1347                 break;
1348               case DBUS_TYPE_BOOLEAN:
1349                 if (!dbus_message_iter_append_boolean_array (&iter, (unsigned char *)data, len))
1350                   goto errorout;
1351                 break;
1352               case DBUS_TYPE_INT32:
1353                 if (!dbus_message_iter_append_int32_array (&iter, (dbus_int32_t *)data, len))
1354                   goto errorout;
1355                 break;
1356               case DBUS_TYPE_UINT32:
1357                 if (!dbus_message_iter_append_uint32_array (&iter, (dbus_uint32_t *)data, len))
1358                   goto errorout;
1359                 break;
1360 #ifdef DBUS_HAVE_INT64
1361               case DBUS_TYPE_INT64:
1362                 if (!dbus_message_iter_append_int64_array (&iter, (dbus_int64_t *)data, len))
1363                   goto errorout;
1364                 break;
1365               case DBUS_TYPE_UINT64:
1366                 if (!dbus_message_iter_append_uint64_array (&iter, (dbus_uint64_t *)data, len))
1367                   goto errorout;
1368                 break;
1369 #endif /* DBUS_HAVE_INT64 */
1370               case DBUS_TYPE_DOUBLE:
1371                 if (!dbus_message_iter_append_double_array (&iter, (double *)data, len))
1372                   goto errorout;
1373                 break;
1374               case DBUS_TYPE_STRING:
1375                 if (!dbus_message_iter_append_string_array (&iter, (const char **)data, len))
1376                   goto errorout;
1377                 break;
1378               case DBUS_TYPE_NIL:
1379               case DBUS_TYPE_ARRAY:
1380               case DBUS_TYPE_NAMED:
1381               case DBUS_TYPE_DICT:
1382                 _dbus_warn ("dbus_message_append_args_valist doesn't support recursive arrays\n");
1383                 goto errorout;
1384               default:
1385                 _dbus_warn ("Unknown field type %d\n", type);
1386                 goto errorout;
1387               }
1388           }
1389           break;
1390           
1391         case DBUS_TYPE_DICT:
1392           _dbus_warn ("dbus_message_append_args_valist doesn't support dicts\n");
1393           goto errorout;
1394         default:
1395           _dbus_warn ("Unknown field type %d\n", type);
1396           goto errorout;
1397         }
1398
1399       type = va_arg (var_args, int);
1400     }
1401
1402   return TRUE;
1403
1404  errorout:
1405   return FALSE;
1406 }
1407
1408
1409 /**
1410  * Gets arguments from a message given a variable argument list.
1411  * The variable argument list should contain the type of the
1412  * argumen followed by a pointer to where the value should be
1413  * stored. The list is terminated with 0.
1414  *
1415  * @param message the message
1416  * @param error error to be filled in on failure
1417  * @param first_arg_type the first argument type
1418  * @param ... location for first argument value, then list of type-location pairs
1419  * @returns #FALSE if the error was set
1420  */
1421 dbus_bool_t
1422 dbus_message_get_args (DBusMessage     *message,
1423                        DBusError       *error,
1424                        int              first_arg_type,
1425                        ...)
1426 {
1427   dbus_bool_t retval;
1428   va_list var_args;
1429
1430   _dbus_return_val_if_fail (message != NULL, FALSE);
1431   _dbus_return_val_if_error_is_set (error, FALSE);
1432   
1433   va_start (var_args, first_arg_type);
1434   retval = dbus_message_get_args_valist (message, error, first_arg_type, var_args);
1435   va_end (var_args);
1436
1437   return retval;
1438 }
1439
1440 /**
1441  * This function takes a va_list for use by language bindings
1442  *
1443  * @todo We need to free the argument data when an error occurs.
1444  *
1445  * @see dbus_message_get_args
1446  * @param message the message
1447  * @param error error to be filled in
1448  * @param first_arg_type type of the first argument
1449  * @param var_args return location for first argument, followed by list of type/location pairs
1450  * @returns #FALSE if error was set
1451  */
1452 dbus_bool_t
1453 dbus_message_get_args_valist (DBusMessage     *message,
1454                               DBusError       *error,
1455                               int              first_arg_type,
1456                               va_list          var_args)
1457 {
1458   DBusMessageIter iter;
1459
1460   _dbus_return_val_if_fail (message != NULL, FALSE);
1461   _dbus_return_val_if_error_is_set (error, FALSE);
1462   
1463   dbus_message_iter_init (message, &iter);
1464   return dbus_message_iter_get_args_valist (&iter, error, first_arg_type, var_args);
1465 }
1466
1467 /**
1468  * Gets arguments from a message iterator given a variable argument list.
1469  * The variable argument list should contain the type of the
1470  * argumen followed by a pointer to where the value should be
1471  * stored. The list is terminated with 0.
1472  *
1473  * @param iter the message iterator 
1474  * @param error error to be filled in on failure
1475  * @param first_arg_type the first argument type
1476  * @param ... location for first argument value, then list of type-location pairs
1477  * @returns #FALSE if the error was set
1478  */
1479 dbus_bool_t
1480 dbus_message_iter_get_args (DBusMessageIter *iter,
1481                             DBusError       *error,
1482                             int              first_arg_type,
1483                             ...)
1484 {
1485   dbus_bool_t retval;
1486   va_list var_args;
1487
1488   _dbus_return_val_if_fail (iter != NULL, FALSE);
1489   _dbus_return_val_if_error_is_set (error, FALSE);
1490   
1491   va_start (var_args, first_arg_type);
1492   retval = dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args);
1493   va_end (var_args);
1494
1495   return retval;
1496 }
1497
1498 /**
1499  * This function takes a va_list for use by language bindings
1500  *
1501  * This function supports #DBUS_TYPE_INT64 and #DBUS_TYPE_UINT64
1502  * only if #DBUS_HAVE_INT64 is defined.
1503  *
1504  * @todo this function (or some lower-level non-convenience function)
1505  * needs better error handling; should allow the application to
1506  * distinguish between out of memory, and bad data from the remote
1507  * app. It also needs to not leak a bunch of args when it gets
1508  * to the arg that's bad, as that would be a security hole
1509  * (allow one app to force another to leak memory)
1510  *
1511  * @todo We need to free the argument data when an error occurs.
1512  *
1513  * @see dbus_message_get_args
1514  * @param iter the message iter
1515  * @param error error to be filled in
1516  * @param first_arg_type type of the first argument
1517  * @param var_args return location for first argument, followed by list of type/location pairs
1518  * @returns #FALSE if error was set
1519  */
1520 dbus_bool_t
1521 dbus_message_iter_get_args_valist (DBusMessageIter *iter,
1522                                    DBusError       *error,
1523                                    int              first_arg_type,
1524                                    va_list          var_args)
1525 {
1526   int spec_type, msg_type, i;
1527   dbus_bool_t retval;
1528
1529   _dbus_return_val_if_fail (iter != NULL, FALSE);
1530   _dbus_return_val_if_error_is_set (error, FALSE);
1531
1532   retval = FALSE;
1533   
1534   spec_type = first_arg_type;
1535   i = 0;
1536   
1537   while (spec_type != 0)
1538     {
1539       msg_type = dbus_message_iter_get_arg_type (iter);      
1540       
1541       if (msg_type != spec_type)
1542         {
1543           dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
1544                           "Argument %d is specified to be of type \"%s\", but "
1545                           "is actually of type \"%s\"\n", i,
1546                           _dbus_type_to_string (spec_type),
1547                           _dbus_type_to_string (msg_type));
1548
1549           goto out;
1550         }
1551
1552       switch (spec_type)
1553         {
1554         case DBUS_TYPE_NIL:
1555           break;
1556         case DBUS_TYPE_BYTE:
1557           {
1558             unsigned char *ptr;
1559
1560             ptr = va_arg (var_args, unsigned char *);
1561
1562             *ptr = dbus_message_iter_get_byte (iter);
1563             break;
1564           }
1565         case DBUS_TYPE_BOOLEAN:
1566           {
1567             dbus_bool_t *ptr;
1568
1569             ptr = va_arg (var_args, dbus_bool_t *);
1570
1571             *ptr = dbus_message_iter_get_boolean (iter);
1572             break;
1573           }
1574         case DBUS_TYPE_INT32:
1575           {
1576             dbus_int32_t *ptr;
1577
1578             ptr = va_arg (var_args, dbus_int32_t *);
1579
1580             *ptr = dbus_message_iter_get_int32 (iter);
1581             break;
1582           }
1583         case DBUS_TYPE_UINT32:
1584           {
1585             dbus_uint32_t *ptr;
1586
1587             ptr = va_arg (var_args, dbus_uint32_t *);
1588
1589             *ptr = dbus_message_iter_get_uint32 (iter);
1590             break;
1591           }
1592 #ifdef DBUS_HAVE_INT64
1593         case DBUS_TYPE_INT64:
1594           {
1595             dbus_int64_t *ptr;
1596
1597             ptr = va_arg (var_args, dbus_int64_t *);
1598
1599             *ptr = dbus_message_iter_get_int64 (iter);
1600             break;
1601           }
1602         case DBUS_TYPE_UINT64:
1603           {
1604             dbus_uint64_t *ptr;
1605
1606             ptr = va_arg (var_args, dbus_uint64_t *);
1607
1608             *ptr = dbus_message_iter_get_uint64 (iter);
1609             break;
1610           }
1611 #endif /* DBUS_HAVE_INT64 */
1612           
1613         case DBUS_TYPE_DOUBLE:
1614           {
1615             double *ptr;
1616
1617             ptr = va_arg (var_args, double *);
1618
1619             *ptr = dbus_message_iter_get_double (iter);
1620             break;
1621           }
1622
1623         case DBUS_TYPE_STRING:
1624           {
1625             char **ptr;
1626
1627             ptr = va_arg (var_args, char **);
1628
1629             *ptr = dbus_message_iter_get_string (iter);
1630
1631             if (!*ptr)
1632               {
1633                 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1634                 goto out;
1635               }
1636             
1637             break;
1638           }
1639
1640         case DBUS_TYPE_NAMED:
1641           {
1642             char **name;
1643             unsigned char **data;
1644             int *len;
1645  
1646             name = va_arg (var_args, char **);
1647             data = va_arg (var_args, unsigned char **);
1648             len = va_arg (var_args, int *);
1649
1650             if (!dbus_message_iter_get_named (iter, name, data, len))
1651               {
1652                 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1653                 goto out;
1654               }
1655           }
1656           break;
1657         case DBUS_TYPE_ARRAY:
1658           {
1659             void **data;
1660             int *len, type;
1661  
1662             type = va_arg (var_args, int);
1663             data = va_arg (var_args, void *);
1664             len = va_arg (var_args, int *);
1665
1666             if (dbus_message_iter_get_array_type (iter) != type)
1667               {
1668                 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
1669                                 "Argument %d is specified to be of type \"array of %s\", but "
1670                                 "is actually of type \"array of %s\"\n", i,
1671                                 _dbus_type_to_string (type),
1672                                 _dbus_type_to_string (dbus_message_iter_get_array_type (iter)));
1673                 goto out;
1674               }
1675             
1676             switch (type)
1677               {
1678               case DBUS_TYPE_BYTE:
1679                 if (!dbus_message_iter_get_byte_array (iter, (unsigned char **)data, len))
1680                   {
1681                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1682                     goto out;
1683                   }
1684                 break;
1685               case DBUS_TYPE_BOOLEAN:
1686                 if (!dbus_message_iter_get_boolean_array (iter, (unsigned char **)data, len))
1687                   {
1688                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1689                     goto out;
1690                   }
1691                 break;
1692               case DBUS_TYPE_INT32:
1693                 if (!dbus_message_iter_get_int32_array (iter, (dbus_int32_t **)data, len))
1694                   {
1695                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1696                     goto out;
1697                   }
1698                 break;
1699               case DBUS_TYPE_UINT32:
1700                 if (!dbus_message_iter_get_uint32_array (iter, (dbus_uint32_t **)data, len))
1701                   {
1702                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1703                     goto out;
1704                   }
1705                 break;
1706 #ifdef DBUS_HAVE_INT64
1707               case DBUS_TYPE_INT64:
1708                 if (!dbus_message_iter_get_int64_array (iter, (dbus_int64_t **)data, len))
1709                   {
1710                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1711                     goto out;
1712                   }
1713                 break;
1714               case DBUS_TYPE_UINT64:
1715                 if (!dbus_message_iter_get_uint64_array (iter, (dbus_uint64_t **)data, len))
1716                   {
1717                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1718                     goto out;
1719                   }
1720                 break;
1721 #endif /* DBUS_HAVE_INT64 */
1722               case DBUS_TYPE_DOUBLE:
1723                 if (!dbus_message_iter_get_double_array (iter, (double **)data, len))
1724                   {
1725                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1726                     goto out;
1727                   }
1728                 break;
1729               case DBUS_TYPE_STRING:
1730                 if (!dbus_message_iter_get_string_array (iter, (char ***)data, len))
1731                   {
1732                     dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1733                     goto out;
1734                   }
1735                 break;
1736               case DBUS_TYPE_NIL:
1737               case DBUS_TYPE_ARRAY:
1738               case DBUS_TYPE_NAMED:
1739               case DBUS_TYPE_DICT:
1740                 _dbus_warn ("dbus_message_get_args_valist doesn't support recursive arrays\n");
1741                 dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
1742                 goto out;
1743               default:
1744                 _dbus_warn ("Unknown field type %d\n", type);
1745                 dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
1746                 goto out;
1747               }
1748           }
1749           break;
1750         case DBUS_TYPE_DICT:
1751           _dbus_warn ("dbus_message_get_args_valist doesn't support dicts\n");
1752           dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
1753           goto out;
1754         default:          
1755           dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
1756           _dbus_warn ("Unknown field type %d\n", spec_type);
1757           goto out;
1758         }
1759       
1760       spec_type = va_arg (var_args, int);
1761       if (spec_type != 0 && !dbus_message_iter_next (iter))
1762         {
1763           dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
1764                           "Message has only %d arguments, but more were expected", i);
1765           goto out;
1766         }
1767
1768       i++;
1769     }
1770   
1771   retval = TRUE;
1772   
1773  out:
1774   
1775   return retval;
1776 }
1777
1778
1779 /**
1780  * Initializes a DBusMessageIter representing the arguments of the
1781  * message passed in.
1782  *
1783  * @param message the message
1784  * @param iter pointer to an iterator to initialize
1785  */
1786 void
1787 dbus_message_iter_init (DBusMessage     *message,
1788                         DBusMessageIter *iter)
1789 {
1790   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
1791
1792   _dbus_return_if_fail (message != NULL);
1793   _dbus_return_if_fail (iter != NULL);
1794   
1795   _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
1796   
1797   real->message = message;
1798   real->parent_iter = NULL;
1799   real->changed_stamp = message->changed_stamp;
1800   
1801   real->type = DBUS_MESSAGE_ITER_TYPE_MESSAGE;
1802   real->pos = 0;
1803   real->end = _dbus_string_get_length (&message->body);
1804   
1805   real->container_start = 0;
1806   real->container_length_pos = 0;
1807   real->wrote_dict_key = 0;
1808   real->array_type_pos = 0;
1809 }
1810
1811 #ifndef DBUS_DISABLE_CHECKS
1812 static dbus_bool_t
1813 dbus_message_iter_check (DBusMessageRealIter *iter)
1814 {
1815   if (iter == NULL)
1816     {
1817       _dbus_warn ("dbus iterator check failed: iterator is NULL\n");
1818       return FALSE;
1819     }
1820   
1821   if (iter->changed_stamp != iter->message->changed_stamp)
1822     {
1823       _dbus_warn ("dbus iterator check failed: invalid iterator, must re-initialize it after modifying the message\n");
1824       return FALSE;
1825     }
1826   
1827   if (iter->pos < 0 || iter->pos > iter->end)
1828     {
1829       _dbus_warn ("dbus iterator check failed: invalid position\n");
1830       return FALSE;
1831     }
1832
1833   return TRUE;
1834 }
1835 #endif /* DBUS_DISABLE_CHECKS */
1836
1837 static int
1838 skip_array_type (DBusMessageRealIter *iter, int pos)
1839 {
1840   const char *data;
1841
1842   do
1843     {
1844       data = _dbus_string_get_const_data_len (&iter->message->body,
1845                                               pos++, 1);
1846     }
1847   while (*data == DBUS_TYPE_ARRAY);
1848   
1849   return pos;
1850 }
1851
1852 static int
1853 dbus_message_iter_get_data_start (DBusMessageRealIter *iter, int *type)
1854 {
1855   const char *data;
1856   int pos, len;
1857   
1858   switch (iter->type)
1859     {
1860     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
1861       data = _dbus_string_get_const_data_len (&iter->message->body,
1862                                               iter->pos, 1);
1863       if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_LAST)
1864         *type = *data;
1865       else
1866         *type = DBUS_TYPE_INVALID;
1867       
1868       return skip_array_type (iter, iter->pos);
1869       
1870     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
1871       data = _dbus_string_get_const_data_len (&iter->message->body,
1872                                               iter->array_type_pos, 1);
1873       if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_LAST)
1874         *type = *data;
1875       else
1876         *type = DBUS_TYPE_INVALID;
1877       
1878       return iter->pos;
1879       
1880     case DBUS_MESSAGE_ITER_TYPE_DICT:
1881       /* Get the length of the string */
1882       len = _dbus_demarshal_uint32 (&iter->message->body,
1883                                     iter->message->byte_order,
1884                                     iter->pos, &pos);
1885       pos = pos + len + 1;
1886
1887       data = _dbus_string_get_const_data_len (&iter->message->body,
1888                                               pos, 1);
1889       if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_LAST)
1890         *type = *data;
1891       else
1892         *type = DBUS_TYPE_INVALID;
1893
1894       return skip_array_type (iter, pos);
1895       
1896     default:
1897       _dbus_assert_not_reached ("Invalid iter type");
1898       break;
1899     }
1900   *type = DBUS_TYPE_INVALID;
1901   return iter->pos;
1902 }
1903
1904
1905 /**
1906  * Checks if an iterator has any more fields.
1907  *
1908  * @param iter the message iter
1909  * @returns #TRUE if there are more fields
1910  * following
1911  */
1912 dbus_bool_t
1913 dbus_message_iter_has_next (DBusMessageIter *iter)
1914 {
1915   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
1916   int end_pos;
1917   int type, pos;
1918
1919   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
1920
1921   if (real->pos >= real->end)
1922     return FALSE;
1923   
1924   pos = dbus_message_iter_get_data_start (real, &type);
1925   
1926   if (!_dbus_marshal_get_arg_end_pos (&real->message->body,
1927                                       real->message->byte_order,
1928                                       type, pos, &end_pos))
1929     return FALSE;
1930   
1931   if (end_pos >= real->end)
1932     return FALSE;
1933
1934   return TRUE;  
1935 }
1936
1937 /**
1938  * Moves the iterator to the next field.
1939  *
1940  * @param iter The message iter
1941  * @returns #TRUE if the iterator was moved to the next field
1942  */
1943 dbus_bool_t
1944 dbus_message_iter_next (DBusMessageIter *iter)
1945 {
1946   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
1947   int end_pos;
1948   int type, pos;
1949
1950   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
1951
1952   pos = dbus_message_iter_get_data_start (real, &type);
1953   
1954   if (!_dbus_marshal_get_arg_end_pos (&real->message->body,
1955                                       real->message->byte_order,
1956                                       type, pos, &end_pos))
1957     return FALSE;
1958
1959   if (end_pos >= real->end)
1960     return FALSE;
1961
1962   real->pos = end_pos;
1963
1964   return TRUE;
1965 }
1966
1967 /**
1968  * Returns the argument type of the argument that the
1969  * message iterator points at.
1970  *
1971  * @param iter the message iter
1972  * @returns the field type
1973  */
1974 int
1975 dbus_message_iter_get_arg_type (DBusMessageIter *iter)
1976 {
1977   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
1978   int type, pos;
1979
1980   _dbus_return_val_if_fail (dbus_message_iter_check (real), DBUS_TYPE_INVALID);
1981
1982   if (real->pos >= real->end)
1983     return DBUS_TYPE_INVALID;
1984
1985   pos = dbus_message_iter_get_data_start (real, &type);
1986   
1987   return type;
1988 }
1989
1990 static int
1991 iter_get_array_type (DBusMessageRealIter *iter, int *array_type_pos)
1992 {
1993   const char *data;
1994   int _array_type_pos;
1995   int len, pos;
1996   
1997   switch (iter->type)
1998     {
1999     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
2000       _array_type_pos = iter->pos + 1;
2001       break;
2002     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
2003       _array_type_pos = iter->array_type_pos + 1;
2004       break;
2005     case DBUS_MESSAGE_ITER_TYPE_DICT:
2006       /* Get the length of the string */
2007       len = _dbus_demarshal_uint32 (&iter->message->body,
2008                                     iter->message->byte_order,
2009                                     iter->pos, &pos);
2010       pos = pos + len + 1;
2011       data = _dbus_string_get_const_data_len (&iter->message->body,
2012                                               pos + 1, 1);
2013       _array_type_pos = pos + 1;
2014       break;
2015     default:
2016       _dbus_assert_not_reached ("wrong iter type");
2017       return DBUS_TYPE_INVALID;
2018     }
2019
2020   if (array_type_pos != NULL)
2021     *array_type_pos = _array_type_pos;
2022   
2023   data = _dbus_string_get_const_data_len (&iter->message->body,
2024                                           _array_type_pos, 1);
2025   if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_LAST)
2026     return  *data;
2027   
2028   return DBUS_TYPE_INVALID;
2029 }
2030
2031
2032 /**
2033  * Returns the element type of the array that the
2034  * message iterator points at. Note that you need
2035  * to check that the iterator points to an array
2036  * prior to using this function.
2037  *
2038  * @param iter the message iter
2039  * @returns the field type
2040  */
2041 int
2042 dbus_message_iter_get_array_type (DBusMessageIter *iter)
2043 {
2044   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2045   int type, pos;
2046
2047   _dbus_return_val_if_fail (dbus_message_iter_check (real), DBUS_TYPE_INVALID);
2048
2049   if (real->pos >= real->end)
2050     return DBUS_TYPE_INVALID;
2051
2052   pos = dbus_message_iter_get_data_start (real, &type);
2053
2054   _dbus_assert (type == DBUS_TYPE_ARRAY);
2055
2056   return iter_get_array_type (real, NULL);
2057 }
2058
2059
2060 /**
2061  * Returns the string value that an iterator may point to.
2062  * Note that you need to check that the iterator points to
2063  * a string value before using this function.
2064  *
2065  * @see dbus_message_iter_get_arg_type
2066  * @param iter the message iter
2067  * @returns the string
2068  */
2069 char *
2070 dbus_message_iter_get_string (DBusMessageIter *iter)
2071 {
2072   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2073   int type, pos;
2074
2075   _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL);
2076
2077   pos = dbus_message_iter_get_data_start (real, &type);
2078   
2079   _dbus_assert (type == DBUS_TYPE_STRING);
2080
2081   return _dbus_demarshal_string (&real->message->body, real->message->byte_order,
2082                                  pos, NULL);
2083 }
2084
2085 /**
2086  * Returns the name and data from a named type that an
2087  * iterator may point to. Note that you need to check that
2088  * the iterator points to a named type before using this
2089  * function.
2090  *
2091  * @see dbus_message_iter_get_arg_type
2092  * @param iter the message iter
2093  * @param name return location for the name
2094  * @param value return location for data
2095  * @param len return location for length of data
2096  * @returns TRUE if get succeed
2097  * 
2098  */
2099 dbus_bool_t
2100 dbus_message_iter_get_named (DBusMessageIter   *iter,
2101                              char             **name,
2102                              unsigned char    **value,
2103                              int               *len)
2104 {
2105   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2106   int type, pos;
2107   char *_name;
2108
2109   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2110
2111   pos = dbus_message_iter_get_data_start (real, &type);
2112   
2113   _dbus_assert (type == DBUS_TYPE_NAMED);
2114   
2115   _name = _dbus_demarshal_string (&real->message->body, real->message->byte_order,
2116                                   pos, &pos);
2117
2118   if (_name == NULL)
2119     return FALSE;
2120   
2121   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
2122                                    pos + 1, NULL, value, len))
2123     {
2124       dbus_free (_name);
2125       return FALSE;
2126     }
2127
2128   *name = _name;
2129   
2130   return TRUE;
2131 }
2132
2133 /**
2134  * Returns the byte value that an iterator may point to.
2135  * Note that you need to check that the iterator points to
2136  * a byte value before using this function.
2137  *
2138  * @see dbus_message_iter_get_arg_type
2139  * @param iter the message iter
2140  * @returns the byte value
2141  */
2142 unsigned char
2143 dbus_message_iter_get_byte (DBusMessageIter *iter)
2144 {
2145   unsigned char value;
2146   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2147   int type, pos;
2148
2149   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2150
2151   pos = dbus_message_iter_get_data_start (real, &type);
2152   
2153   _dbus_assert (type == DBUS_TYPE_BYTE);
2154
2155   value = _dbus_string_get_byte (&real->message->body, pos);
2156   
2157   return value;
2158 }
2159
2160
2161 /**
2162  * Returns the boolean value that an iterator may point to.
2163  * Note that you need to check that the iterator points to
2164  * a boolean value before using this function.
2165  *
2166  * @see dbus_message_iter_get_arg_type
2167  * @param iter the message iter
2168  * @returns the boolean value
2169  */
2170 dbus_bool_t
2171 dbus_message_iter_get_boolean (DBusMessageIter *iter)
2172 {
2173   unsigned char value;
2174   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2175   int type, pos;
2176
2177   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2178
2179   pos = dbus_message_iter_get_data_start (real, &type);
2180   
2181   _dbus_assert (type == DBUS_TYPE_BOOLEAN);
2182
2183   value = _dbus_string_get_byte (&real->message->body, pos);
2184   
2185   return value;
2186 }
2187
2188 /**
2189  * Returns the 32 bit signed integer value that an iterator may point to.
2190  * Note that you need to check that the iterator points to
2191  * a 32-bit integer value before using this function.
2192  *
2193  * @see dbus_message_iter_get_arg_type
2194  * @param iter the message iter
2195  * @returns the integer
2196  */
2197 dbus_int32_t
2198 dbus_message_iter_get_int32 (DBusMessageIter *iter)
2199 {
2200   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2201   int type, pos;
2202
2203   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2204
2205   pos = dbus_message_iter_get_data_start (real, &type);
2206   
2207   _dbus_assert (type == DBUS_TYPE_INT32);
2208   
2209   return _dbus_demarshal_int32 (&real->message->body, real->message->byte_order,
2210                                 pos, NULL);
2211 }
2212
2213 /**
2214  * Returns the 32 bit unsigned integer value that an iterator may point to.
2215  * Note that you need to check that the iterator points to
2216  * a 32-bit unsigned integer value before using this function.
2217  *
2218  * @see dbus_message_iter_get_arg_type
2219  * @param iter the message iter
2220  * @returns the integer
2221  */
2222 dbus_uint32_t
2223 dbus_message_iter_get_uint32 (DBusMessageIter *iter)
2224 {
2225   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2226   int type, pos;
2227
2228   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2229
2230   pos = dbus_message_iter_get_data_start (real, &type);
2231   
2232   _dbus_assert (type == DBUS_TYPE_UINT32);
2233   
2234   return _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
2235                                  pos, NULL);
2236 }
2237
2238 #ifdef DBUS_HAVE_INT64
2239
2240 /**
2241  * Returns the 64 bit signed integer value that an iterator may point
2242  * to.  Note that you need to check that the iterator points to a
2243  * 64-bit integer value before using this function.
2244  *
2245  * This function only exists if #DBUS_HAVE_INT64 is defined.
2246  *
2247  * @see dbus_message_iter_get_arg_type
2248  * @param iter the message iter
2249  * @returns the integer
2250  */
2251 dbus_int64_t
2252 dbus_message_iter_get_int64 (DBusMessageIter *iter)
2253 {
2254   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2255   int type, pos;
2256
2257   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2258
2259   pos = dbus_message_iter_get_data_start (real, &type);
2260   
2261   _dbus_assert (type == DBUS_TYPE_INT64);
2262   
2263   return _dbus_demarshal_int64 (&real->message->body, real->message->byte_order,
2264                                 pos, NULL);
2265 }
2266
2267 /**
2268  * Returns the 64 bit unsigned integer value that an iterator may point to.
2269  * Note that you need to check that the iterator points to
2270  * a 64-bit unsigned integer value before using this function.
2271  * 
2272  * This function only exists if #DBUS_HAVE_INT64 is defined.
2273  * 
2274  * @see dbus_message_iter_get_arg_type
2275  * @param iter the message iter
2276  * @returns the integer
2277  */
2278 dbus_uint64_t
2279 dbus_message_iter_get_uint64 (DBusMessageIter *iter)
2280 {
2281   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2282   int type, pos;
2283
2284   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0);
2285
2286   pos = dbus_message_iter_get_data_start (real, &type);
2287   
2288   _dbus_assert (type == DBUS_TYPE_UINT64);
2289   
2290   return _dbus_demarshal_uint64 (&real->message->body, real->message->byte_order,
2291                                  pos, NULL);
2292 }
2293
2294 #endif /* DBUS_HAVE_INT64 */
2295
2296 /**
2297  * Returns the double value that an iterator may point to.
2298  * Note that you need to check that the iterator points to
2299  * a string value before using this function.
2300  *
2301  * @see dbus_message_iter_get_arg_type
2302  * @param iter the message iter
2303  * @returns the double
2304  */
2305 double
2306 dbus_message_iter_get_double (DBusMessageIter *iter)
2307 {
2308   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2309   int type, pos;
2310
2311   _dbus_return_val_if_fail (dbus_message_iter_check (real), 0.0);
2312
2313   pos = dbus_message_iter_get_data_start (real, &type);
2314   
2315   _dbus_assert (type == DBUS_TYPE_DOUBLE);
2316   
2317   return _dbus_demarshal_double (&real->message->body, real->message->byte_order,
2318                                  pos, NULL);
2319 }
2320
2321 /**
2322  * Initializes an iterator for the array that the iterator
2323  * may point to. Note that you need to check that the iterator
2324  * points to an array prior to using this function.
2325  *
2326  * The array element type is returned in array_type, and the array
2327  * iterator can only be used to get that type of data.
2328  *
2329  * @param iter the iterator
2330  * @param array_iter pointer to an iterator to initialize
2331  * @param array_type gets set to the type of the array elements
2332  * @returns #TRUE on success
2333  */
2334 dbus_bool_t
2335 dbus_message_iter_init_array_iterator (DBusMessageIter *iter,
2336                                        DBusMessageIter *array_iter,
2337                                        int             *array_type)
2338 {
2339   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2340   DBusMessageRealIter *array_real = (DBusMessageRealIter *)array_iter;
2341   int type, pos, len_pos, len, array_type_pos;
2342   int _array_type;
2343
2344   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2345
2346   pos = dbus_message_iter_get_data_start (real, &type);
2347   
2348   _dbus_assert (type == DBUS_TYPE_ARRAY);
2349
2350   _array_type = iter_get_array_type (real, &array_type_pos);
2351   
2352   len_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
2353   len = _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
2354                                 pos, &pos);
2355   
2356   array_real->parent_iter = real;
2357   array_real->message = real->message;
2358   array_real->changed_stamp = real->message->changed_stamp;
2359   
2360   array_real->type = DBUS_MESSAGE_ITER_TYPE_ARRAY;
2361   array_real->pos = pos;
2362   array_real->end = pos + len;
2363   
2364   array_real->container_start = pos;
2365   array_real->container_length_pos = len_pos;
2366   array_real->wrote_dict_key = 0;
2367   array_real->array_type_pos = array_type_pos;
2368   array_real->array_type_done = TRUE;
2369   
2370   if (array_type != NULL)
2371     *array_type = _array_type;
2372   
2373   return TRUE;
2374 }
2375
2376
2377 /**
2378  * Initializes an iterator for the dict that the iterator
2379  * may point to. Note that you need to check that the iterator
2380  * points to a dict prior to using this function.
2381  *
2382  * @param iter the iterator
2383  * @param dict_iter pointer to an iterator to initialize
2384  * @returns #TRUE on success
2385  */
2386 dbus_bool_t
2387 dbus_message_iter_init_dict_iterator (DBusMessageIter *iter,
2388                                       DBusMessageIter *dict_iter)
2389 {
2390   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2391   DBusMessageRealIter *dict_real = (DBusMessageRealIter *)dict_iter;
2392   int type, pos, len_pos, len;
2393
2394   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2395
2396   pos = dbus_message_iter_get_data_start (real, &type);
2397   
2398   _dbus_assert (type == DBUS_TYPE_DICT);
2399
2400   len_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
2401   len = _dbus_demarshal_uint32 (&real->message->body, real->message->byte_order,
2402                                 pos, &pos);
2403   
2404   dict_real->parent_iter = real;
2405   dict_real->message = real->message;
2406   dict_real->changed_stamp = real->message->changed_stamp;
2407   
2408   dict_real->type = DBUS_MESSAGE_ITER_TYPE_DICT;
2409   dict_real->pos = pos;
2410   dict_real->end = pos + len;
2411   
2412   dict_real->container_start = pos;
2413   dict_real->container_length_pos = len_pos;
2414   dict_real->wrote_dict_key = 0;
2415
2416   return TRUE;
2417 }
2418
2419 /**
2420  * Returns the byte array that the iterator may point to.
2421  * Note that you need to check that the iterator points
2422  * to a byte array prior to using this function.
2423  *
2424  * @param iter the iterator
2425  * @param value return location for array values
2426  * @param len return location for length of byte array
2427  * @returns #TRUE on success
2428  */
2429 dbus_bool_t
2430 dbus_message_iter_get_byte_array (DBusMessageIter  *iter,
2431                                   unsigned char   **value,
2432                                   int              *len)
2433 {
2434   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2435   int type, pos;
2436
2437   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2438
2439   pos = dbus_message_iter_get_data_start (real, &type);
2440   
2441   _dbus_assert (type == DBUS_TYPE_ARRAY);
2442
2443   type = iter_get_array_type (real, NULL);
2444
2445   _dbus_assert (type == DBUS_TYPE_BYTE);
2446
2447   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
2448                                    pos, NULL, value, len))
2449     return FALSE;
2450   else
2451     return TRUE;
2452 }
2453
2454 /**
2455  * Returns the boolean array that the iterator may point to. Note that
2456  * you need to check that the iterator points to an array of the
2457  * correct type prior to using this function.
2458  *
2459  * @param iter the iterator
2460  * @param value return location for the array
2461  * @param len return location for the array length
2462  * @returns #TRUE on success
2463  */
2464 dbus_bool_t
2465 dbus_message_iter_get_boolean_array (DBusMessageIter   *iter,
2466                                      unsigned char    **value,
2467                                      int               *len)
2468 {
2469   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2470   int type, pos;
2471
2472   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2473
2474   pos = dbus_message_iter_get_data_start (real, &type);
2475   
2476   _dbus_assert (type == DBUS_TYPE_ARRAY);
2477
2478   type = iter_get_array_type (real, NULL);
2479
2480   _dbus_assert (type == DBUS_TYPE_BOOLEAN);
2481
2482   if (!_dbus_demarshal_byte_array (&real->message->body, real->message->byte_order,
2483                                    pos, NULL, value, len))
2484     return FALSE;
2485   else
2486     return TRUE;
2487 }
2488
2489 /**
2490  * Returns the 32 bit signed integer array that the iterator may point
2491  * to. Note that you need to check that the iterator points to an
2492  * array of the correct type prior to using this function.
2493  *
2494  * @param iter the iterator
2495  * @param value return location for the array
2496  * @param len return location for the array length
2497  * @returns #TRUE on success
2498  */
2499 dbus_bool_t
2500 dbus_message_iter_get_int32_array  (DBusMessageIter *iter,
2501                                     dbus_int32_t   **value,
2502                                     int             *len)
2503 {
2504   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2505   int type, pos;
2506
2507   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2508
2509   pos = dbus_message_iter_get_data_start (real, &type);
2510   
2511   _dbus_assert (type == DBUS_TYPE_ARRAY);
2512
2513   type = iter_get_array_type (real, NULL);
2514   
2515   _dbus_assert (type == DBUS_TYPE_INT32);
2516
2517   if (!_dbus_demarshal_int32_array (&real->message->body, real->message->byte_order,
2518                                     pos, NULL, value, len))
2519     return FALSE;
2520   else
2521     return TRUE;
2522 }
2523
2524 /**
2525  * Returns the 32 bit unsigned integer array that the iterator may point
2526  * to. Note that you need to check that the iterator points to an
2527  * array of the correct type prior to using this function.
2528  *
2529  * @param iter the iterator
2530  * @param value return location for the array
2531  * @param len return location for the array length
2532  * @returns #TRUE on success
2533  */
2534 dbus_bool_t
2535 dbus_message_iter_get_uint32_array  (DBusMessageIter *iter,
2536                                      dbus_uint32_t  **value,
2537                                      int             *len)
2538 {
2539   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2540   int type, pos;
2541
2542   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2543
2544   pos = dbus_message_iter_get_data_start (real, &type);
2545   
2546   _dbus_assert (type == DBUS_TYPE_ARRAY);
2547
2548   type = iter_get_array_type (real, NULL);
2549   _dbus_assert (type == DBUS_TYPE_UINT32);
2550
2551   if (!_dbus_demarshal_uint32_array (&real->message->body, real->message->byte_order,
2552                                     pos, NULL, value, len))
2553     return FALSE;
2554   else
2555     return TRUE;
2556 }
2557
2558 #ifdef DBUS_HAVE_INT64
2559
2560 /**
2561  * Returns the 64 bit signed integer array that the iterator may point
2562  * to. Note that you need to check that the iterator points to an
2563  * array of the correct type prior to using this function.
2564  * 
2565  * This function only exists if #DBUS_HAVE_INT64 is defined.
2566  *
2567  * @param iter the iterator
2568  * @param value return location for the array
2569  * @param len return location for the array length
2570  * @returns #TRUE on success
2571  */
2572 dbus_bool_t
2573 dbus_message_iter_get_int64_array  (DBusMessageIter *iter,
2574                                     dbus_int64_t   **value,
2575                                     int             *len)
2576 {
2577   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2578   int type, pos;
2579
2580   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2581
2582   pos = dbus_message_iter_get_data_start (real, &type);
2583   
2584   _dbus_assert (type == DBUS_TYPE_ARRAY);
2585
2586   type = iter_get_array_type (real, NULL);
2587   
2588   _dbus_assert (type == DBUS_TYPE_INT64);
2589
2590   if (!_dbus_demarshal_int64_array (&real->message->body, real->message->byte_order,
2591                                     pos, NULL, value, len))
2592     return FALSE;
2593   else
2594     return TRUE;
2595 }
2596
2597 /**
2598  * Returns the 64 bit unsigned integer array that the iterator may point
2599  * to. Note that you need to check that the iterator points to an
2600  * array of the correct type prior to using this function.
2601  *
2602  * This function only exists if #DBUS_HAVE_INT64 is defined.
2603  *
2604  * @param iter the iterator
2605  * @param value return location for the array
2606  * @param len return location for the array length
2607  * @returns #TRUE on success
2608  */
2609 dbus_bool_t
2610 dbus_message_iter_get_uint64_array  (DBusMessageIter *iter,
2611                                      dbus_uint64_t  **value,
2612                                      int             *len)
2613 {
2614   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2615   int type, pos;
2616
2617   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2618
2619   pos = dbus_message_iter_get_data_start (real, &type);
2620   
2621   _dbus_assert (type == DBUS_TYPE_ARRAY);
2622
2623   type = iter_get_array_type (real, NULL);
2624   _dbus_assert (type == DBUS_TYPE_UINT64);
2625
2626   if (!_dbus_demarshal_uint64_array (&real->message->body, real->message->byte_order,
2627                                     pos, NULL, value, len))
2628     return FALSE;
2629   else
2630     return TRUE;
2631 }
2632
2633 #endif /* DBUS_HAVE_INT64 */
2634
2635 /**
2636  * Returns the double array that the iterator may point to. Note that
2637  * you need to check that the iterator points to an array of the
2638  * correct type prior to using this function.
2639  *
2640  * @param iter the iterator
2641  * @param value return location for the array
2642  * @param len return location for the array length
2643  * @returns #TRUE on success
2644  */
2645 dbus_bool_t
2646 dbus_message_iter_get_double_array  (DBusMessageIter *iter,
2647                                      double         **value,
2648                                      int             *len)
2649 {
2650   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2651   int type, pos;
2652
2653   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2654
2655   pos = dbus_message_iter_get_data_start (real, &type);
2656   
2657   _dbus_assert (type == DBUS_TYPE_ARRAY);
2658
2659   type = iter_get_array_type (real, NULL);
2660   _dbus_assert (type == DBUS_TYPE_DOUBLE);
2661
2662   if (!_dbus_demarshal_double_array (&real->message->body, real->message->byte_order,
2663                                      pos, NULL, value, len))
2664     return FALSE;
2665   else
2666     return TRUE;
2667 }
2668
2669 /**
2670  * Returns the string array that the iterator may point to.
2671  * Note that you need to check that the iterator points
2672  * to a byte array prior to using this function.
2673  *
2674  * The returned value is a #NULL-terminated array of strings.
2675  * Each string is a separate malloc block, and the array
2676  * itself is a malloc block. You can free this type of
2677  * string array with dbus_free_string_array().
2678  *
2679  * @param iter the iterator
2680  * @param value return location for string values
2681  * @param len return location for length of byte array
2682  * @returns #TRUE on success
2683  */
2684 dbus_bool_t
2685 dbus_message_iter_get_string_array (DBusMessageIter *iter,
2686                                     char          ***value,
2687                                     int             *len)
2688 {
2689   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2690   int type, pos;
2691
2692   _dbus_return_val_if_fail (dbus_message_iter_check (real), FALSE);
2693
2694   pos = dbus_message_iter_get_data_start (real, &type);
2695   
2696   _dbus_assert (type == DBUS_TYPE_ARRAY);
2697
2698   type = iter_get_array_type (real, NULL);
2699   _dbus_assert (type == DBUS_TYPE_STRING);
2700
2701   if (!_dbus_demarshal_string_array (&real->message->body, real->message->byte_order,
2702                                      pos, NULL, value, len))
2703     return FALSE;
2704   else
2705     return TRUE;
2706 }
2707
2708 /**
2709  * Returns the key name fot the dict entry that an iterator
2710  * may point to. Note that you need to check that the iterator
2711  * points to a dict entry before using this function.
2712  *
2713  * @see dbus_message_iter_init_dict_iterator
2714  * @param iter the message iter
2715  * @returns the key name
2716  */
2717 char *
2718 dbus_message_iter_get_dict_key (DBusMessageIter   *iter)
2719 {
2720   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2721
2722   _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL);
2723
2724   _dbus_assert (real->type == DBUS_MESSAGE_ITER_TYPE_DICT);
2725
2726   return _dbus_demarshal_string (&real->message->body, real->message->byte_order,
2727                                  real->pos, NULL);
2728 }
2729
2730 /**
2731  * Initializes a DBusMessageIter pointing to the end of the
2732  * message. This iterator can be used to append data to the
2733  * message.
2734  *
2735  * @param message the message
2736  * @param iter pointer to an iterator to initialize
2737  */
2738 void
2739 dbus_message_append_iter_init (DBusMessage     *message,
2740                                DBusMessageIter *iter)
2741 {
2742   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2743
2744   _dbus_return_if_fail (message != NULL);
2745   _dbus_return_if_fail (iter != NULL);
2746   
2747   real->message = message;
2748   real->parent_iter = NULL;
2749   real->changed_stamp = message->changed_stamp;
2750   
2751   real->type = DBUS_MESSAGE_ITER_TYPE_MESSAGE;
2752   real->end = _dbus_string_get_length (&real->message->body);
2753   real->pos = real->end;
2754   
2755   real->container_length_pos = 0;
2756   real->wrote_dict_key = 0;
2757 }
2758
2759 #ifndef DBUS_DISABLE_CHECKS
2760 static dbus_bool_t
2761 dbus_message_iter_append_check (DBusMessageRealIter *iter)
2762 {
2763   if (iter == NULL)
2764     {
2765       _dbus_warn ("dbus iterator check failed: NULL iterator\n");
2766       return FALSE;
2767     }
2768   
2769   if (iter->message->locked)
2770     {
2771       _dbus_warn ("dbus iterator check failed: message is locked (has already been sent)\n");
2772       return FALSE;
2773     }
2774       
2775   if (iter->changed_stamp != iter->message->changed_stamp)
2776     {
2777       _dbus_warn ("dbus iterator check failed: invalid iterator, must re-initialize it after modifying the message");
2778       return FALSE;
2779     }
2780   
2781   if (iter->pos != iter->end)
2782     {
2783       _dbus_warn ("dbus iterator check failed: can only append at end of message");
2784       return FALSE;
2785     }
2786   
2787   if (iter->pos != _dbus_string_get_length (&iter->message->body))
2788     {
2789       _dbus_warn ("dbus iterator check failed: append pos not at end of message string");
2790       return FALSE;
2791     }
2792
2793   return TRUE;
2794 }
2795 #endif /* DBUS_DISABLE_CHECKS */
2796
2797 static dbus_bool_t
2798 dbus_message_iter_append_type (DBusMessageRealIter *iter,
2799                                int                  type)
2800 {
2801   const char *data;
2802   switch (iter->type)
2803     {
2804     case DBUS_MESSAGE_ITER_TYPE_MESSAGE:
2805       if (!_dbus_string_append_byte (&iter->message->body, type))
2806         return FALSE;
2807       break;
2808       
2809     case DBUS_MESSAGE_ITER_TYPE_ARRAY:
2810       data = _dbus_string_get_const_data_len (&iter->message->body,
2811                                               iter->array_type_pos, 1);
2812       if (type != *data)
2813         {
2814           _dbus_warn ("Appended element of wrong type for array\n");
2815           return FALSE;
2816         }
2817       break;
2818       
2819     case DBUS_MESSAGE_ITER_TYPE_DICT:
2820       if (!iter->wrote_dict_key)
2821         {
2822           _dbus_warn ("Appending dict data before key name\n");
2823           return FALSE;
2824         }
2825       
2826       if (!_dbus_string_append_byte (&iter->message->body, type))
2827         return FALSE;
2828       
2829       break;
2830       
2831     default:
2832       _dbus_assert_not_reached ("Invalid iter type");
2833       break;
2834     }
2835   
2836   return TRUE;
2837 }
2838
2839 static void
2840 dbus_message_iter_update_after_change (DBusMessageRealIter *iter)
2841 {
2842   iter->changed_stamp = iter->message->changed_stamp;
2843   
2844   /* Set new end of iter */
2845   iter->end = _dbus_string_get_length (&iter->message->body);
2846   iter->pos = iter->end;
2847
2848   /* Set container length */
2849   if (iter->type == DBUS_MESSAGE_ITER_TYPE_DICT ||
2850       (iter->type == DBUS_MESSAGE_ITER_TYPE_ARRAY && iter->array_type_done))
2851     _dbus_marshal_set_uint32 (&iter->message->body,
2852                               iter->message->byte_order,
2853                               iter->container_length_pos,
2854                               iter->end - iter->container_start);
2855   
2856   if (iter->parent_iter)
2857     dbus_message_iter_update_after_change (iter->parent_iter);
2858 }
2859
2860 static void
2861 dbus_message_iter_append_done (DBusMessageRealIter *iter)
2862 {
2863   iter->message->changed_stamp++;
2864   dbus_message_iter_update_after_change (iter);
2865   iter->wrote_dict_key = FALSE;
2866 }
2867
2868 /**
2869  * Appends a nil value to the message
2870  *
2871  * @param iter an iterator pointing to the end of the message
2872  * @returns #TRUE on success
2873  */
2874 dbus_bool_t
2875 dbus_message_iter_append_nil (DBusMessageIter *iter)
2876 {
2877   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2878
2879   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
2880
2881   if (!dbus_message_iter_append_type (real, DBUS_TYPE_NIL))
2882     return FALSE;
2883   
2884   dbus_message_iter_append_done (real);
2885   
2886   return TRUE;
2887 }
2888
2889 /**
2890  * Appends a boolean value to the message
2891  *
2892  * @param iter an iterator pointing to the end of the message
2893  * @param value the boolean value
2894  * @returns #TRUE on success
2895  */
2896 dbus_bool_t
2897 dbus_message_iter_append_boolean (DBusMessageIter *iter,
2898                                   dbus_bool_t     value)
2899 {
2900   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2901
2902   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
2903
2904   if (!dbus_message_iter_append_type (real, DBUS_TYPE_BOOLEAN))
2905     return FALSE;
2906   
2907   if (!_dbus_string_append_byte (&real->message->body, (value != FALSE)))
2908     {
2909       _dbus_string_set_length (&real->message->body, real->pos);
2910       return FALSE;
2911     }
2912
2913   dbus_message_iter_append_done (real);
2914   
2915   return TRUE;
2916 }
2917
2918 /**
2919  * Appends a byte to the message
2920  *
2921  * @param iter an iterator pointing to the end of the message
2922  * @param value the byte value
2923  * @returns #TRUE on success
2924  */
2925 dbus_bool_t
2926 dbus_message_iter_append_byte (DBusMessageIter *iter,
2927                                unsigned char    value)
2928 {
2929   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2930
2931   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
2932
2933   if (!dbus_message_iter_append_type (real, DBUS_TYPE_BYTE))
2934     return FALSE;
2935   
2936   if (!_dbus_string_append_byte (&real->message->body, value))
2937     {
2938       _dbus_string_set_length (&real->message->body, real->pos);
2939       return FALSE;
2940     }
2941
2942   dbus_message_iter_append_done (real);
2943   
2944   return TRUE;
2945 }
2946
2947
2948 /**
2949  * Appends a 32 bit signed integer to the message.
2950  *
2951  * @param iter an iterator pointing to the end of the message
2952  * @param value the integer value
2953  * @returns #TRUE on success
2954  */
2955 dbus_bool_t
2956 dbus_message_iter_append_int32   (DBusMessageIter *iter,
2957                                   dbus_int32_t  value)
2958 {
2959   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2960
2961   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
2962
2963   if (!dbus_message_iter_append_type (real, DBUS_TYPE_INT32))
2964     return FALSE;
2965   
2966   if (!_dbus_marshal_int32 (&real->message->body, real->message->byte_order, value))
2967     {
2968       _dbus_string_set_length (&real->message->body, real->pos);
2969       return FALSE;
2970     }
2971
2972   dbus_message_iter_append_done (real);
2973   
2974   return TRUE;
2975 }
2976
2977 /**
2978  * Appends a 32 bit unsigned integer to the message.
2979  *
2980  * @param iter an iterator pointing to the end of the message
2981  * @param value the integer value
2982  * @returns #TRUE on success
2983  */
2984 dbus_bool_t
2985 dbus_message_iter_append_uint32 (DBusMessageIter *iter,
2986                                  dbus_uint32_t    value)
2987 {
2988   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
2989
2990   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
2991
2992   if (!dbus_message_iter_append_type (real, DBUS_TYPE_UINT32))
2993     return FALSE;
2994   
2995   if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, value))
2996     {
2997       _dbus_string_set_length (&real->message->body, real->pos);
2998       return FALSE;
2999     }
3000
3001   dbus_message_iter_append_done (real);
3002   
3003   return TRUE;
3004 }
3005
3006 #ifdef DBUS_HAVE_INT64
3007
3008 /**
3009  * Appends a 64 bit signed integer to the message.
3010  *
3011  * This function only exists if #DBUS_HAVE_INT64 is defined.
3012  *
3013  * @param iter an iterator pointing to the end of the message
3014  * @param value the integer value
3015  * @returns #TRUE on success
3016  */
3017 dbus_bool_t
3018 dbus_message_iter_append_int64   (DBusMessageIter *iter,
3019                                   dbus_int64_t  value)
3020 {
3021   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3022
3023   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3024
3025   if (!dbus_message_iter_append_type (real, DBUS_TYPE_INT64))
3026     return FALSE;
3027   
3028   if (!_dbus_marshal_int64 (&real->message->body, real->message->byte_order, value))
3029     {
3030       _dbus_string_set_length (&real->message->body, real->pos);
3031       return FALSE;
3032     }
3033
3034   dbus_message_iter_append_done (real);
3035   
3036   return TRUE;
3037 }
3038
3039 /**
3040  * Appends a 64 bit unsigned integer to the message.
3041  *
3042  * This function only exists if #DBUS_HAVE_INT64 is defined.
3043  *
3044  * @param iter an iterator pointing to the end of the message
3045  * @param value the integer value
3046  * @returns #TRUE on success
3047  */
3048 dbus_bool_t
3049 dbus_message_iter_append_uint64 (DBusMessageIter *iter,
3050                                  dbus_uint64_t    value)
3051 {
3052   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3053
3054   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3055
3056   if (!dbus_message_iter_append_type (real, DBUS_TYPE_UINT64))
3057     return FALSE;
3058   
3059   if (!_dbus_marshal_uint64 (&real->message->body, real->message->byte_order, value))
3060     {
3061       _dbus_string_set_length (&real->message->body, real->pos);
3062       return FALSE;
3063     }
3064
3065   dbus_message_iter_append_done (real);
3066   
3067   return TRUE;
3068 }
3069
3070 #endif /* DBUS_HAVE_INT64 */
3071
3072 /**
3073  * Appends a double value to the message.
3074  *
3075  * @param iter an iterator pointing to the end of the message
3076  * @param value the double value
3077  * @returns #TRUE on success
3078  */
3079 dbus_bool_t
3080 dbus_message_iter_append_double (DBusMessageIter *iter,
3081                                  double           value)
3082 {
3083   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3084
3085   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3086
3087   if (!dbus_message_iter_append_type (real, DBUS_TYPE_DOUBLE))
3088     return FALSE;
3089   
3090   if (!_dbus_marshal_double (&real->message->body, real->message->byte_order, value))
3091     {
3092       _dbus_string_set_length (&real->message->body, real->pos);
3093       return FALSE;
3094     }
3095
3096   dbus_message_iter_append_done (real);
3097   
3098   return TRUE;
3099 }
3100
3101 /**
3102  * Appends a UTF-8 string to the message.
3103  *
3104  * @param iter an iterator pointing to the end of the message
3105  * @param value the string
3106  * @returns #TRUE on success
3107  */
3108 dbus_bool_t
3109 dbus_message_iter_append_string (DBusMessageIter *iter,
3110                                  const char      *value)
3111 {
3112   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3113
3114   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3115
3116   if (!dbus_message_iter_append_type (real, DBUS_TYPE_STRING))
3117     return FALSE;
3118   
3119   if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value))
3120     {
3121       _dbus_string_set_length (&real->message->body, real->pos);
3122       return FALSE;
3123     }
3124
3125   dbus_message_iter_append_done (real);
3126   
3127   return TRUE;
3128 }
3129
3130 /**
3131  * Appends a named type data chunk to the message. A named
3132  * type is simply an arbitrary UTF-8 string used as a type
3133  * tag, plus an array of arbitrary bytes to be interpreted
3134  * according to the type tag.
3135  *
3136  * @param iter an iterator pointing to the end of the message
3137  * @param name the name of the type
3138  * @param data the binary data used to store the value
3139  * @param len the length of the binary data in bytes
3140  * @returns #TRUE on success
3141  */
3142 dbus_bool_t
3143 dbus_message_iter_append_named (DBusMessageIter      *iter,
3144                                 const char           *name,
3145                                 const unsigned char  *data,
3146                                 int                   len)
3147 {
3148   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3149
3150   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3151
3152   if (!dbus_message_iter_append_type (real, DBUS_TYPE_NAMED))
3153     return FALSE;
3154   
3155    if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, name))
3156     {
3157       _dbus_string_set_length (&real->message->body, real->pos);
3158       return FALSE;
3159     }
3160    
3161   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, data, len))
3162     {
3163       _dbus_string_set_length (&real->message->body, real->pos);
3164       return FALSE;
3165     }
3166
3167   dbus_message_iter_append_done (real);
3168   
3169   return TRUE;
3170 }
3171
3172
3173 /**
3174  * Appends a dict key name to the message. The iterator used
3175  * must point to a dict.
3176  *
3177  * @param iter an iterator pointing to the end of the message
3178  * @param value the string
3179  * @returns #TRUE on success
3180  */
3181 dbus_bool_t
3182 dbus_message_iter_append_dict_key (DBusMessageIter *iter,
3183                                    const char      *value)
3184 {
3185   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3186
3187   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3188   _dbus_assert (real->type == DBUS_MESSAGE_ITER_TYPE_DICT);
3189   
3190   if (real->wrote_dict_key)
3191     {
3192       _dbus_warn ("Appendinging multiple dict key names\n");
3193       return FALSE;
3194     }
3195   
3196   if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value))
3197     {
3198       return FALSE;
3199     }
3200
3201   dbus_message_iter_append_done (real);
3202   real->wrote_dict_key = TRUE;
3203   
3204   return TRUE;
3205 }
3206
3207 static dbus_bool_t
3208 array_iter_type_mark_done (DBusMessageRealIter *iter)
3209 {
3210   int len_pos;
3211   
3212   if (iter->type == DBUS_MESSAGE_ITER_TYPE_ARRAY)
3213     array_iter_type_mark_done (iter->parent_iter);
3214   else
3215     return TRUE;
3216
3217   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&iter->message->body),
3218                                sizeof (dbus_uint32_t));
3219
3220   /* Empty length for now, backfill later */
3221   if (!_dbus_marshal_uint32 (&iter->message->body, iter->message->byte_order, 0))
3222     {
3223       _dbus_string_set_length (&iter->message->body, iter->pos);
3224       return FALSE;
3225     }
3226
3227   iter->container_start = _dbus_string_get_length (&iter->message->body);
3228   iter->container_length_pos = len_pos;
3229   iter->array_type_done = TRUE;
3230
3231   return TRUE;
3232 }
3233
3234 static dbus_bool_t
3235 append_array_type (DBusMessageRealIter *real,
3236                    int                  element_type,
3237                    dbus_bool_t         *array_type_done,
3238                    int                 *array_type_pos)
3239 {
3240   int existing_element_type;
3241   
3242   if (!dbus_message_iter_append_type (real, DBUS_TYPE_ARRAY))
3243     return FALSE;
3244   
3245   if (real->type == DBUS_MESSAGE_ITER_TYPE_ARRAY &&
3246       real->array_type_done)
3247     {
3248       existing_element_type = iter_get_array_type (real, array_type_pos);
3249       if (existing_element_type != element_type)
3250         {
3251           _dbus_warn ("Appending array of %s, when expecting array of %s\n",
3252                       _dbus_type_to_string (element_type),
3253                       _dbus_type_to_string (existing_element_type));
3254           _dbus_string_set_length (&real->message->body, real->pos);
3255           return FALSE;
3256         }
3257       if (array_type_done != NULL)
3258           *array_type_done = TRUE;
3259     }
3260   else
3261     {
3262       if (array_type_pos != NULL)
3263         *array_type_pos = _dbus_string_get_length (&real->message->body);
3264       
3265       /* Append element type */
3266       if (!_dbus_string_append_byte (&real->message->body, element_type))
3267         {
3268           _dbus_string_set_length (&real->message->body, real->pos);
3269           return FALSE;
3270         }
3271
3272       if (array_type_done != NULL)
3273         *array_type_done = element_type != DBUS_TYPE_ARRAY;
3274       
3275       if (element_type != DBUS_TYPE_ARRAY &&
3276           !array_iter_type_mark_done (real))
3277         return FALSE;
3278     }
3279
3280   return TRUE;
3281 }
3282
3283 /**
3284  * Appends an array to the message and initializes an iterator that
3285  * can be used to append to the array.
3286  *
3287  * @param iter an iterator pointing to the end of the message
3288  * @param array_iter pointer to an iter that will be initialized
3289  * @param element_type the type of the array elements
3290  * @returns #TRUE on success
3291  */
3292 dbus_bool_t
3293 dbus_message_iter_append_array (DBusMessageIter      *iter,
3294                                 DBusMessageIter      *array_iter,
3295                                 int                   element_type)
3296 {
3297   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3298   DBusMessageRealIter *array_real = (DBusMessageRealIter *)array_iter;
3299   int len_pos;
3300   int array_type_pos;
3301   dbus_bool_t array_type_done;
3302
3303   if (element_type == DBUS_TYPE_NIL)
3304     {
3305       _dbus_warn ("Can't create NIL arrays\n");
3306       return FALSE;
3307     }
3308   
3309   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3310
3311   if (!append_array_type (real, element_type, &array_type_done, &array_type_pos))
3312     return FALSE;
3313
3314   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&real->message->body), sizeof (dbus_uint32_t));
3315
3316   if (array_type_done)
3317     {
3318       /* Empty length for now, backfill later */
3319       if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, 0))
3320         {
3321           _dbus_string_set_length (&real->message->body, real->pos);
3322           return FALSE;
3323         }
3324     }
3325   
3326   array_real->parent_iter = real;
3327   array_real->message = real->message;
3328   array_real->changed_stamp = real->message->changed_stamp;
3329   
3330   array_real->type = DBUS_MESSAGE_ITER_TYPE_ARRAY;
3331   array_real->pos = _dbus_string_get_length (&real->message->body);
3332   array_real->end = array_real->end;
3333   
3334   array_real->container_start = array_real->pos;
3335   array_real->container_length_pos = len_pos;
3336   array_real->wrote_dict_key = 0;
3337   array_real->array_type_done = array_type_done;
3338   array_real->array_type_pos = array_type_pos;
3339
3340   dbus_message_iter_append_done (array_real);
3341   
3342   return TRUE;
3343 }
3344
3345 /**
3346  * Appends a dict to the message and initializes an iterator that
3347  * can be used to append to the dict.
3348  *
3349  * @param iter an iterator pointing to the end of the message
3350  * @param dict_iter pointer to an iter that will be initialized
3351  * @returns #TRUE on success
3352  */
3353 dbus_bool_t
3354 dbus_message_iter_append_dict (DBusMessageIter      *iter,
3355                                DBusMessageIter      *dict_iter)
3356 {
3357   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3358   DBusMessageRealIter *dict_real = (DBusMessageRealIter *)dict_iter;
3359   int len_pos;
3360
3361   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3362
3363   if (!dbus_message_iter_append_type (real, DBUS_TYPE_DICT))
3364     return FALSE;
3365
3366   len_pos = _DBUS_ALIGN_VALUE (_dbus_string_get_length (&real->message->body), sizeof (dbus_uint32_t));
3367
3368   /* Empty length for now, backfill later */
3369   if (!_dbus_marshal_uint32 (&real->message->body, real->message->byte_order, 0))
3370     {
3371       _dbus_string_set_length (&real->message->body, real->pos);
3372       return FALSE;
3373     }
3374   
3375   dict_real->parent_iter = real;
3376   dict_real->message = real->message;
3377   dict_real->changed_stamp = real->message->changed_stamp;
3378   
3379   dict_real->type = DBUS_MESSAGE_ITER_TYPE_DICT;
3380   dict_real->pos = _dbus_string_get_length (&real->message->body);
3381   dict_real->end = dict_real->end;
3382   
3383   dict_real->container_start = dict_real->pos;
3384   dict_real->container_length_pos = len_pos;
3385   dict_real->wrote_dict_key = 0;
3386
3387   dbus_message_iter_append_done (dict_real);
3388   
3389   return TRUE;
3390 }
3391
3392
3393 /**
3394  * Appends a boolean array to the message.
3395  *
3396  * @param iter an iterator pointing to the end of the message
3397  * @param value the array
3398  * @param len the length of the array
3399  * @returns #TRUE on success
3400  */
3401 dbus_bool_t
3402 dbus_message_iter_append_boolean_array (DBusMessageIter     *iter,
3403                                         unsigned const char *value,
3404                                         int                  len)
3405 {
3406   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3407
3408   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3409
3410   if (!append_array_type (real, DBUS_TYPE_BOOLEAN, NULL, NULL))
3411     return FALSE;
3412   
3413   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, value, len))
3414     {
3415       _dbus_string_set_length (&real->message->body, real->pos);
3416       return FALSE;
3417     }
3418
3419   dbus_message_iter_append_done (real);
3420   
3421   return TRUE;
3422 }
3423
3424 /**
3425  * Appends a 32 bit signed integer array to the message.
3426  *
3427  * @param iter an iterator pointing to the end of the message
3428  * @param value the array
3429  * @param len the length of the array
3430  * @returns #TRUE on success
3431  */
3432 dbus_bool_t
3433 dbus_message_iter_append_int32_array (DBusMessageIter    *iter,
3434                                       const dbus_int32_t *value,
3435                                       int                 len)
3436 {
3437   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3438
3439   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3440
3441   if (!append_array_type (real, DBUS_TYPE_INT32, NULL, NULL))
3442     return FALSE;
3443   
3444   if (!_dbus_marshal_int32_array (&real->message->body, real->message->byte_order, value, len))
3445     {
3446       _dbus_string_set_length (&real->message->body, real->pos);
3447       return FALSE;
3448     }
3449
3450   dbus_message_iter_append_done (real);
3451   
3452   return TRUE;
3453 }
3454
3455 /**
3456  * Appends a 32 bit unsigned integer array to the message.
3457  *
3458  * @param iter an iterator pointing to the end of the message
3459  * @param value the array
3460  * @param len the length of the array
3461  * @returns #TRUE on success
3462  */
3463 dbus_bool_t
3464 dbus_message_iter_append_uint32_array (DBusMessageIter     *iter,
3465                                        const dbus_uint32_t *value,
3466                                        int                  len)
3467 {
3468   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3469
3470   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3471
3472   if (!append_array_type (real, DBUS_TYPE_UINT32, NULL, NULL))
3473     return FALSE;
3474   
3475   if (!_dbus_marshal_uint32_array (&real->message->body, real->message->byte_order, value, len))
3476     {
3477       _dbus_string_set_length (&real->message->body, real->pos);
3478       return FALSE;
3479     }
3480
3481   dbus_message_iter_append_done (real);
3482   
3483   return TRUE;
3484 }
3485
3486 #ifdef DBUS_HAVE_INT64
3487
3488 /**
3489  * Appends a 64 bit signed integer array to the message.
3490  *
3491  * This function only exists if #DBUS_HAVE_INT64 is defined.
3492  *
3493  * @param iter an iterator pointing to the end of the message
3494  * @param value the array
3495  * @param len the length of the array
3496  * @returns #TRUE on success
3497  */
3498 dbus_bool_t
3499 dbus_message_iter_append_int64_array (DBusMessageIter    *iter,
3500                                       const dbus_int64_t *value,
3501                                       int                 len)
3502 {
3503   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3504
3505   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3506
3507   if (!append_array_type (real, DBUS_TYPE_INT64, NULL, NULL))
3508     return FALSE;
3509   
3510   if (!_dbus_marshal_int64_array (&real->message->body, real->message->byte_order, value, len))
3511     {
3512       _dbus_string_set_length (&real->message->body, real->pos);
3513       return FALSE;
3514     }
3515
3516   dbus_message_iter_append_done (real);
3517   
3518   return TRUE;
3519 }
3520
3521 /**
3522  * Appends a 64 bit unsigned integer array to the message.
3523  *
3524  * This function only exists if #DBUS_HAVE_INT64 is defined.
3525  *
3526  * @param iter an iterator pointing to the end of the message
3527  * @param value the array
3528  * @param len the length of the array
3529  * @returns #TRUE on success
3530  */
3531 dbus_bool_t
3532 dbus_message_iter_append_uint64_array (DBusMessageIter     *iter,
3533                                        const dbus_uint64_t *value,
3534                                        int                  len)
3535 {
3536   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3537
3538   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3539
3540   if (!append_array_type (real, DBUS_TYPE_UINT64, NULL, NULL))
3541     return FALSE;
3542   
3543   if (!_dbus_marshal_uint64_array (&real->message->body, real->message->byte_order, value, len))
3544     {
3545       _dbus_string_set_length (&real->message->body, real->pos);
3546       return FALSE;
3547     }
3548
3549   dbus_message_iter_append_done (real);
3550   
3551   return TRUE;
3552 }
3553 #endif /* DBUS_HAVE_INT64 */
3554
3555 /**
3556  * Appends a double array to the message.
3557  *
3558  * @param iter an iterator pointing to the end of the message
3559  * @param value the array
3560  * @param len the length of the array
3561  * @returns #TRUE on success
3562  */
3563 dbus_bool_t
3564 dbus_message_iter_append_double_array (DBusMessageIter *iter,
3565                                        const double    *value,
3566                                        int              len)
3567 {
3568   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3569
3570   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3571
3572   if (!append_array_type (real, DBUS_TYPE_DOUBLE, NULL, NULL))
3573     return FALSE;
3574   
3575   if (!_dbus_marshal_double_array (&real->message->body, real->message->byte_order, value, len))
3576     {
3577       _dbus_string_set_length (&real->message->body, real->pos);
3578       return FALSE;
3579     }
3580
3581   dbus_message_iter_append_done (real);
3582   
3583   return TRUE;
3584 }
3585
3586 /**
3587  * Appends a byte array to the message.
3588  *
3589  * @param iter an iterator pointing to the end of the message
3590  * @param value the array
3591  * @param len the length of the array
3592  * @returns #TRUE on success
3593  */
3594 dbus_bool_t
3595 dbus_message_iter_append_byte_array (DBusMessageIter     *iter,
3596                                      unsigned const char *value,
3597                                      int                  len)
3598 {
3599   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3600
3601   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3602
3603   if (!append_array_type (real, DBUS_TYPE_BYTE, NULL, NULL))
3604     return FALSE;
3605   
3606   if (!_dbus_marshal_byte_array (&real->message->body, real->message->byte_order, value, len))
3607     {
3608       _dbus_string_set_length (&real->message->body, real->pos);
3609       return FALSE;
3610     }
3611
3612   dbus_message_iter_append_done (real);
3613   
3614   return TRUE;
3615 }
3616
3617 /**
3618  * Appends a string array to the message.
3619  *
3620  * @param iter an iterator pointing to the end of the message
3621  * @param value the array
3622  * @param len the length of the array
3623  * @returns #TRUE on success
3624  */
3625 dbus_bool_t
3626 dbus_message_iter_append_string_array (DBusMessageIter *iter,
3627                                        const char     **value,
3628                                        int              len)
3629 {
3630   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
3631
3632   _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
3633
3634   if (!append_array_type (real, DBUS_TYPE_STRING, NULL, NULL))
3635     return FALSE;
3636   
3637   if (!_dbus_marshal_string_array (&real->message->body, real->message->byte_order, value, len))
3638     {
3639       _dbus_string_set_length (&real->message->body, real->pos);
3640       return FALSE;
3641     }
3642
3643   dbus_message_iter_append_done (real);
3644   
3645   return TRUE;
3646 }
3647
3648 /**
3649  * Sets the message sender.
3650  *
3651  * @param message the message
3652  * @param sender the sender
3653  * @returns #FALSE if not enough memory
3654  */
3655 dbus_bool_t
3656 dbus_message_set_sender (DBusMessage  *message,
3657                          const char   *sender)
3658 {
3659   _dbus_return_val_if_fail (message != NULL, FALSE);
3660   _dbus_return_val_if_fail (!message->locked, FALSE);
3661
3662   if (sender == NULL)
3663     {
3664       delete_string_field (message, FIELD_SENDER);
3665       return TRUE;
3666     }
3667   else
3668     {
3669       return set_string_field (message,
3670                                FIELD_SENDER,
3671                                sender);
3672     }
3673 }
3674
3675 /**
3676  * Sets a flag indicating that the message is an error reply
3677  * message, i.e. an "exception" rather than a normal response.
3678  *
3679  * @param message the message
3680  * @param is_error_reply #TRUE if this is an error message.
3681  */
3682 void
3683 dbus_message_set_is_error (DBusMessage *message,
3684                            dbus_bool_t  is_error_reply)
3685 {
3686   char *header;
3687
3688   _dbus_return_if_fail (message != NULL);
3689   _dbus_return_if_fail (!message->locked);
3690   
3691   header = _dbus_string_get_data_len (&message->header, 1, 1);
3692   
3693   if (is_error_reply)
3694     *header |= DBUS_HEADER_FLAG_ERROR;
3695   else
3696     *header &= ~DBUS_HEADER_FLAG_ERROR;    
3697 }
3698
3699 /**
3700  * Returns #TRUE if the message is an error
3701  * reply to some previous message we sent.
3702  *
3703  * @param message the message
3704  * @returns #TRUE if the message is an error
3705  */
3706 dbus_bool_t
3707 dbus_message_get_is_error (DBusMessage *message)
3708 {
3709   const char *header;
3710
3711   _dbus_return_val_if_fail (message != NULL, FALSE);
3712   
3713   header = _dbus_string_get_const_data_len (&message->header, 1, 1);
3714
3715   return (*header & DBUS_HEADER_FLAG_ERROR) != 0;
3716 }
3717
3718 /**
3719  * Gets the service which originated this message,
3720  * or #NULL if unknown or inapplicable.
3721  *
3722  * @param message the message
3723  * @returns the service name or #NULL
3724  */
3725 const char*
3726 dbus_message_get_sender (DBusMessage *message)
3727 {
3728   _dbus_return_val_if_fail (message != NULL, NULL);
3729   
3730   return get_string_field (message, FIELD_SENDER, NULL);
3731 }
3732
3733 /**
3734  * Checks whether the message has the given name.
3735  * If the message has no name or has a different
3736  * name, returns #FALSE.
3737  *
3738  * @param message the message
3739  * @param name the name to check (must not be #NULL)
3740  * 
3741  * @returns #TRUE if the message has the given name
3742  */
3743 dbus_bool_t
3744 dbus_message_has_name (DBusMessage *message,
3745                        const char  *name)
3746 {
3747   const char *n;
3748
3749   _dbus_return_val_if_fail (message != NULL, FALSE);
3750   _dbus_return_val_if_fail (name != NULL, FALSE);
3751   
3752   n = dbus_message_get_name (message);
3753
3754   if (n && strcmp (n, name) == 0)
3755     return TRUE;
3756   else
3757     return FALSE;
3758 }
3759
3760 /**
3761  * Checks whether the message was sent to the given service.  If the
3762  * message has no service specified or has a different name, returns
3763  * #FALSE.
3764  *
3765  * @param message the message
3766  * @param service the service to check (must not be #NULL)
3767  * 
3768  * @returns #TRUE if the message has the given destination service
3769  */
3770 dbus_bool_t
3771 dbus_message_has_destination (DBusMessage  *message,
3772                               const char   *service)
3773 {
3774   const char *s;
3775
3776   _dbus_return_val_if_fail (message != NULL, FALSE);
3777   _dbus_return_val_if_fail (service != NULL, FALSE);
3778   
3779   s = dbus_message_get_destination (message);
3780
3781   if (s && strcmp (s, service) == 0)
3782     return TRUE;
3783   else
3784     return FALSE;
3785 }
3786
3787 /**
3788  * Checks whether the message has the given service as its sender.  If
3789  * the message has no sender specified or has a different sender,
3790  * returns #FALSE. Note that if a peer application owns multiple
3791  * services, its messages will have only one of those services as the
3792  * sender (usually the base service). So you can't use this
3793  * function to prove the sender didn't own service Foo, you can
3794  * only use it to prove that it did.
3795  *
3796  * @param message the message
3797  * @param service the service to check (must not be #NULL)
3798  * 
3799  * @returns #TRUE if the message has the given origin service
3800  */
3801 dbus_bool_t
3802 dbus_message_has_sender (DBusMessage  *message,
3803                          const char   *service)
3804 {
3805   const char *s;
3806
3807   _dbus_assert (service != NULL);
3808   
3809   s = dbus_message_get_sender (message);
3810
3811   if (s && strcmp (s, service) == 0)
3812     return TRUE;
3813   else
3814     return FALSE;
3815 }
3816
3817 /**
3818  * Sets a #DBusError based on the contents of the given
3819  * message. The error is only set if the message
3820  * is an error message, as in dbus_message_get_is_error().
3821  * The name of the error is set to the name of the message,
3822  * and the error message is set to the first argument
3823  * if the argument exists and is a string.
3824  *
3825  * The return value indicates whether the error was set (the error is
3826  * set if and only if the message is an error message).
3827  * So you can check for an error reply and convert it to DBusError
3828  * in one go.
3829  *
3830  * @param error the error to set
3831  * @param message the message to set it from
3832  * @returns #TRUE if dbus_message_get_is_error() returns #TRUE for the message
3833  */
3834 dbus_bool_t
3835 dbus_set_error_from_message (DBusError   *error,
3836                              DBusMessage *message)
3837 {
3838   char *str;
3839
3840   _dbus_return_val_if_fail (message != NULL, FALSE);
3841   _dbus_return_val_if_error_is_set (error, FALSE);
3842   
3843   if (!dbus_message_get_is_error (message))
3844     return FALSE;
3845
3846   str = NULL;
3847   dbus_message_get_args (message, NULL,
3848                          DBUS_TYPE_STRING, &str,
3849                          DBUS_TYPE_INVALID);
3850
3851   dbus_set_error (error, dbus_message_get_name (message),
3852                   str ? "%s" : NULL, str);
3853
3854   dbus_free (str);
3855   
3856   return TRUE;
3857 }
3858
3859 /** @} */
3860
3861 /**
3862  * @addtogroup DBusMessageInternals
3863  *
3864  * @{
3865  */
3866 /**
3867  * @typedef DBusMessageLoader
3868  *
3869  * The DBusMessageLoader object encapsulates the process of converting
3870  * a byte stream into a series of DBusMessage. It buffers the incoming
3871  * bytes as efficiently as possible, and generates a queue of
3872  * messages. DBusMessageLoader is typically used as part of a
3873  * DBusTransport implementation. The DBusTransport then hands off
3874  * the loaded messages to a DBusConnection, making the messages
3875  * visible to the application.
3876  *
3877  * @todo write tests for break-loader that a) randomly delete header
3878  * fields and b) set string fields to zero-length and other funky
3879  * values.
3880  * 
3881  */
3882
3883 /* we definitely use signed ints for sizes, so don't exceed
3884  * _DBUS_INT_MAX; and add 16 for paranoia, since a message
3885  * over 128M is pretty nuts anyhow.
3886  */
3887
3888 /**
3889  * The maximum sane message size.
3890  */
3891 #define MAX_SANE_MESSAGE_SIZE (_DBUS_INT_MAX/16)
3892
3893 /**
3894  * Implementation details of DBusMessageLoader.
3895  * All members are private.
3896  */
3897 struct DBusMessageLoader
3898 {
3899   int refcount;        /**< Reference count. */
3900
3901   DBusString data;     /**< Buffered data */
3902   
3903   DBusList *messages;  /**< Complete messages. */
3904
3905   long max_message_size; /**< Maximum size of a message */
3906   
3907   unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
3908
3909   unsigned int corrupted : 1; /**< We got broken data, and are no longer working */
3910 };
3911
3912 /**
3913  * The initial buffer size of the message loader.
3914  * 
3915  * @todo this should be based on min header size plus some average
3916  * body size, or something. Or rather, the min header size only, if we
3917  * want to try to read only the header, store that in a DBusMessage,
3918  * then read only the body and store that, etc., depends on
3919  * how we optimize _dbus_message_loader_get_buffer() and what
3920  * the exact message format is.
3921  */
3922 #define INITIAL_LOADER_DATA_LEN 32
3923
3924 /**
3925  * Creates a new message loader. Returns #NULL if memory can't
3926  * be allocated.
3927  *
3928  * @returns new loader, or #NULL.
3929  */
3930 DBusMessageLoader*
3931 _dbus_message_loader_new (void)
3932 {
3933   DBusMessageLoader *loader;
3934
3935   loader = dbus_new0 (DBusMessageLoader, 1);
3936   if (loader == NULL)
3937     return NULL;
3938   
3939   loader->refcount = 1;
3940
3941   /* Try to cap message size at something that won't *totally* hose
3942    * the system if we have a couple of them.
3943    */
3944   loader->max_message_size = _DBUS_ONE_MEGABYTE * 32;
3945   
3946   if (!_dbus_string_init (&loader->data))
3947     {
3948       dbus_free (loader);
3949       return NULL;
3950     }
3951
3952   /* preallocate the buffer for speed, ignore failure */
3953   _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
3954   _dbus_string_set_length (&loader->data, 0);
3955   
3956   return loader;
3957 }
3958
3959 /**
3960  * Increments the reference count of the loader.
3961  *
3962  * @param loader the loader.
3963  */
3964 void
3965 _dbus_message_loader_ref (DBusMessageLoader *loader)
3966 {
3967   loader->refcount += 1;
3968 }
3969
3970 /**
3971  * Decrements the reference count of the loader and finalizes the
3972  * loader when the count reaches zero.
3973  *
3974  * @param loader the loader.
3975  */
3976 void
3977 _dbus_message_loader_unref (DBusMessageLoader *loader)
3978 {
3979   loader->refcount -= 1;
3980   if (loader->refcount == 0)
3981     {
3982       _dbus_list_foreach (&loader->messages,
3983                           (DBusForeachFunction) dbus_message_unref,
3984                           NULL);
3985       _dbus_list_clear (&loader->messages);
3986       _dbus_string_free (&loader->data);
3987       dbus_free (loader);
3988     }
3989 }
3990
3991 /**
3992  * Gets the buffer to use for reading data from the network.  Network
3993  * data is read directly into an allocated buffer, which is then used
3994  * in the DBusMessage, to avoid as many extra memcpy's as possible.
3995  * The buffer must always be returned immediately using
3996  * _dbus_message_loader_return_buffer(), even if no bytes are
3997  * successfully read.
3998  *
3999  * @todo this function can be a lot more clever. For example
4000  * it can probably always return a buffer size to read exactly
4001  * the body of the next message, thus avoiding any memory wastage
4002  * or reallocs.
4003  *
4004  * @todo we need to enforce a max length on strings in header fields.
4005  * 
4006  * @param loader the message loader.
4007  * @param buffer the buffer
4008  */
4009 void
4010 _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
4011                                  DBusString        **buffer)
4012 {
4013   _dbus_assert (!loader->buffer_outstanding);
4014
4015   *buffer = &loader->data;
4016   
4017   loader->buffer_outstanding = TRUE;
4018 }
4019
4020 /**
4021  * The smallest header size that can occur. 
4022  * (It won't be valid)
4023  */
4024 #define DBUS_MINIMUM_HEADER_SIZE 16
4025
4026 /** Pack four characters as in "abcd" into a uint32 */
4027 #define FOUR_CHARS_TO_UINT32(a, b, c, d)                \
4028                       ((((dbus_uint32_t)a) << 24) |     \
4029                        (((dbus_uint32_t)b) << 16) |     \
4030                        (((dbus_uint32_t)c) << 8)  |     \
4031                        ((dbus_uint32_t)d))
4032
4033 /** DBUS_HEADER_FIELD_NAME packed into a dbus_uint32_t */
4034 #define DBUS_HEADER_FIELD_NAME_AS_UINT32    \
4035   FOUR_CHARS_TO_UINT32 ('n', 'a', 'm', 'e')
4036
4037 /** DBUS_HEADER_FIELD_SERVICE packed into a dbus_uint32_t */
4038 #define DBUS_HEADER_FIELD_SERVICE_AS_UINT32 \
4039   FOUR_CHARS_TO_UINT32 ('s', 'r', 'v', 'c')
4040
4041 /** DBUS_HEADER_FIELD_REPLY packed into a dbus_uint32_t */
4042 #define DBUS_HEADER_FIELD_REPLY_AS_UINT32   \
4043   FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y')
4044
4045 /** DBUS_HEADER_FIELD_SENDER Packed into a dbus_uint32_t */
4046 #define DBUS_HEADER_FIELD_SENDER_AS_UINT32  \
4047   FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r')
4048
4049 static dbus_bool_t
4050 decode_string_field (const DBusString   *data,
4051                      HeaderField         fields[FIELD_LAST],
4052                      int                 pos,
4053                      int                 type,
4054                      int                 field,
4055                      const char         *field_name)
4056 {
4057   DBusString tmp;
4058   int string_data_pos;
4059   
4060   if (fields[field].offset >= 0)
4061     {
4062       _dbus_verbose ("%s field provided twice\n",
4063                      field_name);
4064       return FALSE;
4065     }
4066
4067   if (type != DBUS_TYPE_STRING)
4068     {
4069       _dbus_verbose ("%s field has wrong type %s\n",
4070                      field_name, _dbus_type_to_string (type));
4071       return FALSE;
4072     }
4073
4074   /* skip padding after typecode, skip string length;
4075    * we assume that the string arg has already been validated
4076    * for sanity and UTF-8
4077    */
4078   string_data_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4;
4079   _dbus_assert (string_data_pos < _dbus_string_get_length (data));
4080   
4081   _dbus_string_init_const (&tmp,
4082                            _dbus_string_get_const_data (data) + string_data_pos);
4083
4084   if (field == FIELD_NAME)
4085     {
4086       if (!_dbus_string_validate_name (&tmp, 0, _dbus_string_get_length (&tmp)))
4087         {
4088           _dbus_verbose ("%s field has invalid content \"%s\"\n",
4089                          field_name, _dbus_string_get_const_data (&tmp));
4090           return FALSE;
4091         }
4092       
4093       if (_dbus_string_starts_with_c_str (&tmp,
4094                                           DBUS_NAMESPACE_LOCAL_MESSAGE))
4095         {
4096           _dbus_verbose ("Message is in the local namespace\n");
4097           return FALSE;
4098         }
4099     }
4100   else
4101     {
4102       if (!_dbus_string_validate_service (&tmp, 0, _dbus_string_get_length (&tmp)))
4103         {
4104           _dbus_verbose ("%s field has invalid content \"%s\"\n",
4105                          field_name, _dbus_string_get_const_data (&tmp));
4106           return FALSE;
4107         }
4108     }
4109   
4110   fields[field].offset = _DBUS_ALIGN_VALUE (pos, 4);
4111   
4112 #if 0
4113   _dbus_verbose ("Found field %s name at offset %d\n",
4114                  field_name, fields[field].offset);
4115 #endif
4116
4117   return TRUE;
4118 }
4119
4120 static dbus_bool_t
4121 decode_header_data (const DBusString   *data,
4122                     int                 header_len,
4123                     int                 byte_order,
4124                     HeaderField         fields[FIELD_LAST],
4125                     int                *message_padding)
4126 {
4127   const char *field;
4128   int pos, new_pos;
4129   int i;
4130   int type;
4131   
4132   if (header_len < 16)
4133     return FALSE;
4134   
4135   i = 0;
4136   while (i < FIELD_LAST)
4137     {
4138       fields[i].offset = -1;
4139       ++i;
4140     }
4141   
4142   fields[FIELD_HEADER_LENGTH].offset = 4;
4143   fields[FIELD_BODY_LENGTH].offset = 8;   
4144   fields[FIELD_CLIENT_SERIAL].offset = 12;
4145   
4146   /* Now handle the named fields. A real named field is at least 4
4147    * bytes for the name, plus a type code (1 byte) plus padding.  So
4148    * if we have less than 8 bytes left, it must be alignment padding,
4149    * not a field. While >= 8 bytes can't be entirely alignment
4150    * padding.
4151    */  
4152   pos = 16;
4153   while ((pos + 7) < header_len)
4154     {
4155       pos = _DBUS_ALIGN_VALUE (pos, 4);
4156       
4157       if ((pos + 4) > header_len)
4158         return FALSE;      
4159       
4160       field =_dbus_string_get_const_data_len (data, pos, 4);
4161       pos += 4;
4162
4163       _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field);
4164       
4165       if (!_dbus_marshal_validate_type (data, pos, &type, &pos))
4166         {
4167           _dbus_verbose ("Failed to validate type of named header field\n");
4168           return FALSE;
4169         }
4170       
4171       if (!_dbus_marshal_validate_arg (data, byte_order, 0, type, -1, pos, &new_pos))
4172         {
4173           _dbus_verbose ("Failed to validate argument to named header field\n");
4174           return FALSE;
4175         }
4176
4177       if (new_pos > header_len)
4178         {
4179           _dbus_verbose ("Named header field tries to extend beyond header length\n");
4180           return FALSE;
4181         }
4182       
4183       switch (DBUS_UINT32_FROM_BE (*(int*)field))
4184         {
4185         case DBUS_HEADER_FIELD_SERVICE_AS_UINT32:
4186           if (!decode_string_field (data, fields, pos, type,
4187                                     FIELD_SERVICE,
4188                                     DBUS_HEADER_FIELD_SERVICE))
4189             return FALSE;
4190           break;
4191
4192         case DBUS_HEADER_FIELD_NAME_AS_UINT32:
4193           if (!decode_string_field (data, fields, pos, type,
4194                                     FIELD_NAME,
4195                                     DBUS_HEADER_FIELD_NAME))
4196             return FALSE;
4197           break;
4198
4199         case DBUS_HEADER_FIELD_SENDER_AS_UINT32:
4200           if (!decode_string_field (data, fields, pos, type,
4201                                     FIELD_SENDER,
4202                                     DBUS_HEADER_FIELD_SENDER))
4203             return FALSE;
4204           break;
4205           
4206         case DBUS_HEADER_FIELD_REPLY_AS_UINT32:
4207           if (fields[FIELD_REPLY_SERIAL].offset >= 0)
4208             {
4209               _dbus_verbose ("%s field provided twice\n",
4210                              DBUS_HEADER_FIELD_REPLY);
4211               return FALSE;
4212             }
4213
4214           if (type != DBUS_TYPE_UINT32)
4215             {
4216               _dbus_verbose ("%s field has wrong type\n", DBUS_HEADER_FIELD_REPLY);
4217               return FALSE;
4218             }
4219           
4220           fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos, 4);
4221
4222           _dbus_verbose ("Found reply serial at offset %d\n",
4223                          fields[FIELD_REPLY_SERIAL].offset);
4224           break;
4225
4226         default:
4227           _dbus_verbose ("Ignoring an unknown header field: %c%c%c%c at offset %d\n",
4228                          field[0], field[1], field[2], field[3], pos);
4229         }
4230       
4231       pos = new_pos;
4232     }
4233
4234   if (pos < header_len)
4235     {
4236       /* Alignment padding, verify that it's nul */
4237       _dbus_assert ((header_len - pos) < 8);
4238
4239       if (!_dbus_string_validate_nul (data,
4240                                       pos, (header_len - pos)))
4241         {
4242           _dbus_verbose ("header alignment padding is not nul\n");
4243           return FALSE;
4244         }
4245     }
4246
4247   /* Name field is mandatory */
4248   if (fields[FIELD_NAME].offset < 0)
4249     {
4250       _dbus_verbose ("No %s field provided\n",
4251                      DBUS_HEADER_FIELD_NAME);
4252       return FALSE;
4253     }
4254   
4255   if (message_padding)
4256     *message_padding = header_len - pos;  
4257   
4258   return TRUE;
4259 }
4260
4261 /**
4262  * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
4263  * indicating to the loader how many bytes of the buffer were filled
4264  * in. This function must always be called, even if no bytes were
4265  * successfully read.
4266  *
4267  * @param loader the loader.
4268  * @param buffer the buffer.
4269  * @param bytes_read number of bytes that were read into the buffer.
4270  */
4271 void
4272 _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
4273                                     DBusString         *buffer,
4274                                     int                 bytes_read)
4275 {
4276   _dbus_assert (loader->buffer_outstanding);
4277   _dbus_assert (buffer == &loader->data);
4278
4279   loader->buffer_outstanding = FALSE;
4280 }
4281
4282 /**
4283  * Converts buffered data into messages.
4284  *
4285  * @param loader the loader.
4286  * @returns #TRUE if we had enough memory to finish.
4287  */
4288 dbus_bool_t
4289 _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
4290 {
4291   if (loader->corrupted)
4292     return TRUE;
4293
4294   while (_dbus_string_get_length (&loader->data) >= 16)
4295     {
4296       DBusMessage *message;      
4297       const char *header_data;
4298       int byte_order, header_len, body_len, header_padding;
4299       dbus_uint32_t header_len_unsigned, body_len_unsigned;
4300       
4301       header_data = _dbus_string_get_const_data_len (&loader->data, 0, 16);
4302
4303       _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
4304
4305       if (header_data[2] != DBUS_MAJOR_PROTOCOL_VERSION)
4306         {
4307           _dbus_verbose ("Message has protocol version %d ours is %d\n",
4308                          (int) header_data[2], DBUS_MAJOR_PROTOCOL_VERSION);
4309           loader->corrupted = TRUE;
4310           return TRUE;
4311         }
4312       
4313       byte_order = header_data[0];
4314
4315       if (byte_order != DBUS_LITTLE_ENDIAN &&
4316           byte_order != DBUS_BIG_ENDIAN)
4317         {
4318           _dbus_verbose ("Message with bad byte order '%c' received\n",
4319                          byte_order);
4320           loader->corrupted = TRUE;
4321           return TRUE;
4322         }
4323
4324       header_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 4);
4325       body_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 8);
4326
4327       if (header_len_unsigned < 16)
4328         {
4329           _dbus_verbose ("Message had broken too-small header length %u\n",
4330                          header_len_unsigned);
4331           loader->corrupted = TRUE;
4332           return TRUE;
4333         }
4334
4335       if (header_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE ||
4336           body_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE)
4337         {
4338           _dbus_verbose ("Header or body length too large (%u %u)\n",
4339                          header_len_unsigned,
4340                          body_len_unsigned);
4341           loader->corrupted = TRUE;
4342           return TRUE;
4343         }
4344
4345       /* Now that we know the values are in signed range, get
4346        * rid of stupid unsigned, just causes bugs
4347        */
4348       header_len = header_len_unsigned;
4349       body_len = body_len_unsigned;
4350
4351       if (_DBUS_ALIGN_VALUE (header_len, 8) != header_len_unsigned)
4352         {
4353           
4354           _dbus_verbose ("header length %d is not aligned to 8 bytes\n",
4355                          header_len);
4356           loader->corrupted = TRUE;
4357           return TRUE;
4358         }
4359       
4360       if (header_len + body_len > loader->max_message_size)
4361         {
4362           _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %ld\n",
4363                          header_len, body_len, loader->max_message_size);
4364           loader->corrupted = TRUE;
4365           return TRUE;
4366         }
4367
4368       if (_dbus_string_get_length (&loader->data) >= (header_len + body_len))
4369         {
4370           HeaderField fields[FIELD_LAST];
4371           int i;
4372           int next_arg;          
4373
4374 #if 0
4375           _dbus_verbose_bytes_of_string (&loader->data, 0, header_len + body_len);
4376 #endif    
4377           if (!decode_header_data (&loader->data, header_len, byte_order,
4378                                    fields, &header_padding))
4379             {
4380               _dbus_verbose ("Header was invalid\n");
4381               loader->corrupted = TRUE;
4382               return TRUE;
4383             }
4384           
4385           next_arg = header_len;
4386           while (next_arg < (header_len + body_len))
4387             {
4388               int type;
4389               int prev = next_arg;
4390
4391               if (!_dbus_marshal_validate_type (&loader->data, next_arg,
4392                                                 &type, &next_arg))
4393                 {
4394                   _dbus_verbose ("invalid typecode at offset %d\n", prev);
4395                   loader->corrupted = TRUE;
4396                   return TRUE;
4397                 }
4398       
4399               if (!_dbus_marshal_validate_arg (&loader->data,
4400                                                byte_order,
4401                                                0,
4402                                                type, -1,
4403                                                next_arg,
4404                                                &next_arg))
4405                 {
4406                   _dbus_verbose ("invalid type data at %d, next_arg\n", next_arg);
4407                   loader->corrupted = TRUE;
4408                   return TRUE;
4409                 }
4410
4411               _dbus_assert (next_arg > prev);
4412             }
4413           
4414           if (next_arg > (header_len + body_len))
4415             {
4416               _dbus_verbose ("end of last arg at %d but message has len %d+%d=%d\n",
4417                              next_arg, header_len, body_len,
4418                              header_len + body_len);
4419               loader->corrupted = TRUE;
4420               return TRUE;
4421             }
4422
4423           message = dbus_message_new_empty_header ();
4424           if (message == NULL)
4425             {
4426               _dbus_verbose ("Failed to allocate empty message\n");
4427               return FALSE;
4428             }
4429
4430           message->byte_order = byte_order;
4431           message->header_padding = header_padding;
4432           
4433           /* Copy in the offsets we found */
4434           i = 0;
4435           while (i < FIELD_LAST)
4436             {
4437               message->header_fields[i] = fields[i];
4438               ++i;
4439             }
4440           
4441           if (!_dbus_list_append (&loader->messages, message))
4442             {
4443               _dbus_verbose ("Failed to append new message to loader queue\n");
4444               dbus_message_unref (message);
4445               return FALSE;
4446             }
4447
4448           _dbus_assert (_dbus_string_get_length (&message->header) == 0);
4449           _dbus_assert (_dbus_string_get_length (&message->body) == 0);
4450
4451           _dbus_assert (_dbus_string_get_length (&loader->data) >=
4452                         (header_len + body_len));
4453           
4454           if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0))
4455             {
4456               _dbus_verbose ("Failed to move header into new message\n");
4457               _dbus_list_remove_last (&loader->messages, message);
4458               dbus_message_unref (message);
4459               return FALSE;
4460             }
4461           
4462           if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0))
4463             {
4464               dbus_bool_t result;
4465
4466               _dbus_verbose ("Failed to move body into new message\n");
4467               
4468               /* put the header back, we'll try again later */
4469               result = _dbus_string_copy_len (&message->header, 0, header_len,
4470                                               &loader->data, 0);
4471               _dbus_assert (result); /* because DBusString never reallocs smaller */
4472
4473               _dbus_list_remove_last (&loader->messages, message);
4474               dbus_message_unref (message);
4475               return FALSE;
4476             }
4477
4478           _dbus_assert (_dbus_string_get_length (&message->header) == header_len);
4479           _dbus_assert (_dbus_string_get_length (&message->body) == body_len);
4480
4481           /* Fill in caches (we checked the types of these fields
4482            * earlier)
4483            */
4484           message->reply_serial = get_uint_field (message,
4485                                                   FIELD_REPLY_SERIAL);
4486           message->client_serial = get_uint_field (message,
4487                                                    FIELD_CLIENT_SERIAL);
4488           
4489           _dbus_verbose ("Loaded message %p\n", message);
4490         }
4491       else
4492         return TRUE;
4493     }
4494
4495   return TRUE;
4496 }
4497
4498 /**
4499  * Peeks at first loaded message, returns #NULL if no messages have
4500  * been queued.
4501  *
4502  * @param loader the loader.
4503  * @returns the next message, or #NULL if none.
4504  */
4505 DBusMessage*
4506 _dbus_message_loader_peek_message (DBusMessageLoader *loader)
4507 {
4508   if (loader->messages)
4509     return loader->messages->data;
4510   else
4511     return NULL;
4512 }
4513
4514 /**
4515  * Pops a loaded message (passing ownership of the message
4516  * to the caller). Returns #NULL if no messages have been
4517  * queued.
4518  *
4519  * @param loader the loader.
4520  * @returns the next message, or #NULL if none.
4521  */
4522 DBusMessage*
4523 _dbus_message_loader_pop_message (DBusMessageLoader *loader)
4524 {
4525   return _dbus_list_pop_first (&loader->messages);
4526 }
4527
4528 /**
4529  * Pops a loaded message inside a list link (passing ownership of the
4530  * message and link to the caller). Returns #NULL if no messages have
4531  * been loaded.
4532  *
4533  * @param loader the loader.
4534  * @returns the next message link, or #NULL if none.
4535  */
4536 DBusList*
4537 _dbus_message_loader_pop_message_link (DBusMessageLoader *loader)
4538 {
4539   return _dbus_list_pop_first_link (&loader->messages);
4540 }
4541
4542 /**
4543  * Returns a popped message link, used to undo a pop.
4544  *
4545  * @param loader the loader
4546  * @param link the link with a message in it
4547  */
4548 void
4549 _dbus_message_loader_putback_message_link (DBusMessageLoader  *loader,
4550                                            DBusList           *link)
4551 {
4552   _dbus_list_prepend_link (&loader->messages, link);
4553 }
4554
4555 /**
4556  * Checks whether the loader is confused due to bad data.
4557  * If messages are received that are invalid, the
4558  * loader gets confused and gives up permanently.
4559  * This state is called "corrupted."
4560  *
4561  * @param loader the loader
4562  * @returns #TRUE if the loader is hosed.
4563  */
4564 dbus_bool_t
4565 _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
4566 {
4567   return loader->corrupted;
4568 }
4569
4570 /**
4571  * Sets the maximum size message we allow.
4572  *
4573  * @param loader the loader
4574  * @param size the max message size in bytes
4575  */
4576 void
4577 _dbus_message_loader_set_max_message_size (DBusMessageLoader  *loader,
4578                                            long                size)
4579 {
4580   if (size > MAX_SANE_MESSAGE_SIZE)
4581     {
4582       _dbus_verbose ("clamping requested max message size %ld to %d\n",
4583                      size, MAX_SANE_MESSAGE_SIZE);
4584       size = MAX_SANE_MESSAGE_SIZE;
4585     }
4586   loader->max_message_size = size;
4587 }
4588
4589 /**
4590  * Gets the maximum allowed message size in bytes.
4591  *
4592  * @param loader the loader
4593  * @returns max size in bytes
4594  */
4595 long
4596 _dbus_message_loader_get_max_message_size (DBusMessageLoader  *loader)
4597 {
4598   return loader->max_message_size;
4599 }
4600
4601 /** @} */
4602 #ifdef DBUS_BUILD_TESTS
4603 #include "dbus-test.h"
4604 #include <stdio.h>
4605
4606 static void
4607 message_iter_test (DBusMessage *message)
4608 {
4609   DBusMessageIter iter, dict, array, array2;
4610   char *str;
4611   unsigned char *data;
4612   dbus_int32_t *our_int_array;
4613   int len;
4614   
4615   dbus_message_iter_init (message, &iter);
4616
4617   /* String tests */
4618   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
4619     _dbus_assert_not_reached ("Argument type isn't string");
4620
4621   str = dbus_message_iter_get_string (&iter);
4622   if (strcmp (str, "Test string") != 0)
4623     _dbus_assert_not_reached ("Strings differ");
4624   dbus_free (str);
4625
4626   if (!dbus_message_iter_next (&iter))
4627     _dbus_assert_not_reached ("Reached end of arguments");
4628
4629   /* Signed integer tests */
4630   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT32)
4631     _dbus_assert_not_reached ("Argument type isn't int32");
4632
4633   if (dbus_message_iter_get_int32 (&iter) != -0x12345678)
4634     _dbus_assert_not_reached ("Signed integers differ");
4635
4636   if (!dbus_message_iter_next (&iter))
4637     _dbus_assert_not_reached ("Reached end of fields");
4638   
4639   /* Unsigned integer tests */
4640   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32)
4641     _dbus_assert_not_reached ("Argument type isn't int32");
4642
4643   if (dbus_message_iter_get_uint32 (&iter) != 0xedd1e)
4644     _dbus_assert_not_reached ("Unsigned integers differ");
4645
4646   if (!dbus_message_iter_next (&iter))
4647     _dbus_assert_not_reached ("Reached end of arguments");
4648
4649   /* Double tests */
4650   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DOUBLE)
4651     _dbus_assert_not_reached ("Argument type isn't double");
4652
4653   if (dbus_message_iter_get_double (&iter) != 3.14159)
4654     _dbus_assert_not_reached ("Doubles differ");
4655
4656   if (!dbus_message_iter_next (&iter))
4657     _dbus_assert_not_reached ("Reached end of arguments");
4658
4659   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)
4660     _dbus_assert_not_reached ("Argument type not an array");
4661
4662   if (dbus_message_iter_get_array_type (&iter) != DBUS_TYPE_DOUBLE)
4663     _dbus_assert_not_reached ("Array type not double");
4664
4665   
4666   if (!dbus_message_iter_init_array_iterator (&iter, &array, NULL))
4667     _dbus_assert_not_reached ("Array init failed");
4668
4669   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_DOUBLE)
4670     _dbus_assert_not_reached ("Argument type isn't double");
4671
4672   if (dbus_message_iter_get_double (&array) != 1.5)
4673     _dbus_assert_not_reached ("Unsigned integers differ");
4674
4675   if (!dbus_message_iter_next (&array))
4676     _dbus_assert_not_reached ("Reached end of arguments");
4677
4678   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_DOUBLE)
4679     _dbus_assert_not_reached ("Argument type isn't double");
4680
4681   if (dbus_message_iter_get_double (&array) != 2.5)
4682     _dbus_assert_not_reached ("Unsigned integers differ");
4683
4684   if (dbus_message_iter_next (&array))
4685     _dbus_assert_not_reached ("Didn't reach end of arguments");
4686   
4687   if (!dbus_message_iter_next (&iter))
4688     _dbus_assert_not_reached ("Reached end of arguments");
4689   
4690
4691   /* dict */
4692
4693   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT)
4694     _dbus_assert_not_reached ("not dict type");
4695      
4696   if (!dbus_message_iter_init_dict_iterator (&iter, &dict))
4697     _dbus_assert_not_reached ("dict iter failed");
4698
4699   str = dbus_message_iter_get_dict_key (&dict);
4700   if (str == NULL || strcmp (str, "test") != 0)
4701     _dbus_assert_not_reached ("wrong dict key");
4702   dbus_free (str);
4703
4704   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_UINT32)
4705     _dbus_assert_not_reached ("wrong dict entry type");
4706
4707   if (dbus_message_iter_get_uint32 (&dict) != 0xDEADBEEF)
4708     _dbus_assert_not_reached ("wrong dict entry value");
4709
4710   if (!dbus_message_iter_next (&dict))
4711     _dbus_assert_not_reached ("reached end of dict");
4712   
4713   /* array of array of int32 (in dict) */
4714
4715   str = dbus_message_iter_get_dict_key (&dict);
4716   if (str == NULL || strcmp (str, "array") != 0)
4717     _dbus_assert_not_reached ("wrong dict key");
4718   dbus_free (str);
4719   
4720   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_ARRAY)
4721     _dbus_assert_not_reached ("Argument type not an array");
4722
4723   if (dbus_message_iter_get_array_type (&dict) != DBUS_TYPE_ARRAY)
4724     _dbus_assert_not_reached ("Array type not array");
4725
4726   if (!dbus_message_iter_init_array_iterator (&dict, &array, NULL))
4727     _dbus_assert_not_reached ("Array init failed");
4728
4729   if (dbus_message_iter_get_arg_type (&array) != DBUS_TYPE_ARRAY)
4730     _dbus_assert_not_reached ("Argument type isn't array");
4731   
4732   if (dbus_message_iter_get_array_type (&array) != DBUS_TYPE_INT32)
4733     _dbus_assert_not_reached ("Array type not int32");
4734   
4735   if (!dbus_message_iter_init_array_iterator (&array, &array2, NULL))
4736     _dbus_assert_not_reached ("Array init failed");
4737
4738   if (dbus_message_iter_get_arg_type (&array2) != DBUS_TYPE_INT32)
4739     _dbus_assert_not_reached ("Argument type isn't int32");
4740
4741   if (dbus_message_iter_get_int32 (&array2) != 0x12345678)
4742     _dbus_assert_not_reached ("Signed integers differ");
4743
4744   if (!dbus_message_iter_next (&array2))
4745     _dbus_assert_not_reached ("Reached end of arguments");
4746
4747   if (dbus_message_iter_get_int32 (&array2) != 0x23456781)
4748     _dbus_assert_not_reached ("Signed integers differ");
4749
4750   if (dbus_message_iter_next (&array2))
4751     _dbus_assert_not_reached ("Didn't reached end of arguments");
4752
4753   if (!dbus_message_iter_next (&array))
4754     _dbus_assert_not_reached ("Reached end of arguments");
4755
4756   if (dbus_message_iter_get_array_type (&array) != DBUS_TYPE_INT32)
4757     _dbus_assert_not_reached ("Array type not int32");
4758
4759   if (!dbus_message_iter_get_int32_array (&array,
4760                                           &our_int_array,
4761                                           &len))
4762     _dbus_assert_not_reached ("couldn't get int32 array");
4763
4764   _dbus_assert (len == 3);
4765   _dbus_assert (our_int_array[0] == 0x34567812 &&
4766                 our_int_array[1] == 0x45678123 &&
4767                 our_int_array[2] == 0x56781234);
4768   dbus_free (our_int_array);
4769   
4770   if (dbus_message_iter_next (&array))
4771     _dbus_assert_not_reached ("Didn't reach end of array");
4772
4773   if (dbus_message_iter_next (&dict))
4774     _dbus_assert_not_reached ("Didn't reach end of dict");
4775   
4776   if (!dbus_message_iter_next (&iter))
4777     _dbus_assert_not_reached ("Reached end of arguments");
4778   
4779   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_BYTE)
4780     {
4781       _dbus_warn ("type was: %d\n", dbus_message_iter_get_arg_type (&iter));
4782       _dbus_assert_not_reached ("wrong type after dict (should be byte)");
4783     }
4784   
4785   if (dbus_message_iter_get_byte (&iter) != 0xF0)
4786     _dbus_assert_not_reached ("wrong value after dict");
4787
4788
4789   if (!dbus_message_iter_next (&iter))
4790     _dbus_assert_not_reached ("Reached end of arguments");
4791   
4792   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_NIL)
4793     _dbus_assert_not_reached ("not a nil type");
4794   
4795   if (!dbus_message_iter_next (&iter))
4796     _dbus_assert_not_reached ("Reached end of arguments");
4797   
4798   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_NAMED)
4799     _dbus_assert_not_reached ("wrong type after dict");
4800
4801   if (!dbus_message_iter_get_named (&iter, &str, &data, &len))
4802     _dbus_assert_not_reached ("failed to get named");
4803
4804   _dbus_assert (strcmp (str, "named")==0);
4805   _dbus_assert (len == 5);
4806   _dbus_assert (strcmp (data, "data")==0);
4807   dbus_free (str);
4808   dbus_free (data);
4809   
4810   if (dbus_message_iter_next (&iter))
4811     _dbus_assert_not_reached ("Didn't reach end of arguments");
4812 }
4813
4814
4815 static dbus_bool_t
4816 check_message_handling_type (DBusMessageIter *iter,
4817                              int type)
4818 {
4819   DBusMessageIter child_iter;
4820   
4821   switch (type)
4822     {
4823     case DBUS_TYPE_NIL:
4824       break;
4825     case DBUS_TYPE_BYTE:
4826       dbus_message_iter_get_byte (iter);
4827       break;
4828     case DBUS_TYPE_BOOLEAN:
4829       dbus_message_iter_get_boolean (iter);
4830       break;
4831     case DBUS_TYPE_INT32:
4832       dbus_message_iter_get_int32 (iter);
4833       break;
4834     case DBUS_TYPE_UINT32:
4835       dbus_message_iter_get_uint32 (iter);
4836       break;
4837     case DBUS_TYPE_INT64:
4838 #ifdef DBUS_HAVE_INT64
4839       dbus_message_iter_get_int64 (iter);
4840 #endif
4841       break;
4842     case DBUS_TYPE_UINT64:
4843 #ifdef DBUS_HAVE_INT64
4844       dbus_message_iter_get_uint64 (iter);
4845 #endif
4846       break;
4847     case DBUS_TYPE_DOUBLE:
4848       dbus_message_iter_get_double (iter);
4849       break;
4850     case DBUS_TYPE_STRING:
4851       {
4852         char *str;
4853         str = dbus_message_iter_get_string (iter);
4854         if (str == NULL)
4855           {
4856             _dbus_warn ("NULL string in message\n");
4857             return FALSE;
4858           }
4859         dbus_free (str);
4860       }
4861       break;
4862     case DBUS_TYPE_NAMED:
4863       {
4864         char *name;
4865         unsigned char *data;
4866         int len;
4867         
4868         if (!dbus_message_iter_get_named (iter, &name, &data, &len))
4869           {
4870             _dbus_warn ("error reading name from named type\n");
4871             return FALSE;
4872           }
4873         dbus_free (data);
4874         dbus_free (name);
4875       }
4876       break;
4877     case DBUS_TYPE_ARRAY:
4878       {
4879         int array_type;
4880
4881         if (!dbus_message_iter_init_array_iterator (iter, &child_iter, &array_type))
4882           {
4883             _dbus_warn ("Failed to init array iterator\n");
4884             return FALSE;
4885           }
4886
4887         while (dbus_message_iter_has_next (&child_iter))
4888           {
4889             if (!check_message_handling_type (&child_iter, array_type))
4890               {
4891                 _dbus_warn ("error in array element\n");
4892                 return FALSE;
4893               }
4894             
4895             if (!dbus_message_iter_next (&child_iter))
4896               break;
4897           }
4898       }
4899       break;
4900     case DBUS_TYPE_DICT:
4901       {
4902         int entry_type;
4903         char *key;
4904         
4905         if (!dbus_message_iter_init_dict_iterator (iter, &child_iter))
4906           {
4907             _dbus_warn ("Failed to init dict iterator\n");
4908             return FALSE;
4909           }
4910
4911         while ((entry_type = dbus_message_iter_get_arg_type (&child_iter)) != DBUS_TYPE_INVALID)
4912           {
4913             key = dbus_message_iter_get_dict_key (&child_iter);
4914             if (key == NULL)
4915               {
4916                 _dbus_warn ("error reading dict key\n");
4917                 return FALSE;
4918               }
4919             dbus_free (key);
4920             
4921             if (!check_message_handling_type (&child_iter, entry_type))
4922               {
4923                 _dbus_warn ("error in dict value\n");
4924                 return FALSE;
4925               }
4926             
4927             if (!dbus_message_iter_next (&child_iter))
4928               break;
4929           }
4930       }
4931       break;
4932       
4933     default:
4934       _dbus_warn ("unknown type %d\n", type);
4935       return FALSE;
4936       break;
4937     }
4938   return TRUE;
4939 }
4940   
4941   
4942 static dbus_bool_t
4943 check_message_handling (DBusMessage *message)
4944 {
4945   DBusMessageIter iter;
4946   int type;
4947   dbus_bool_t retval;
4948   dbus_uint32_t client_serial;
4949   
4950   retval = FALSE;
4951   
4952   client_serial = dbus_message_get_serial (message);
4953
4954   /* can't use set_serial due to the assertions at the start of it */
4955   set_uint_field (message, FIELD_CLIENT_SERIAL,
4956                   client_serial);
4957   
4958   if (client_serial != dbus_message_get_serial (message))
4959     {
4960       _dbus_warn ("get/set cycle for client_serial did not succeed\n");
4961       goto failed;
4962     }
4963   
4964   /* If we implement message_set_arg (message, n, value)
4965    * then we would want to test it here
4966    */
4967
4968   dbus_message_iter_init (message, &iter);
4969   while ((type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
4970     {
4971       if (!check_message_handling_type (&iter, type))
4972         goto failed;
4973
4974       if (!dbus_message_iter_next (&iter))
4975         break;
4976     }
4977   
4978   retval = TRUE;
4979   
4980  failed:
4981   return retval;
4982 }
4983
4984 static dbus_bool_t
4985 check_have_valid_message (DBusMessageLoader *loader)
4986 {
4987   DBusMessage *message;
4988   dbus_bool_t retval;
4989
4990   message = NULL;
4991   retval = FALSE;
4992
4993   if (!_dbus_message_loader_queue_messages (loader))
4994     _dbus_assert_not_reached ("no memory to queue messages");
4995   
4996   if (_dbus_message_loader_get_is_corrupted (loader))
4997     {
4998       _dbus_warn ("loader corrupted on message that was expected to be valid\n");
4999       goto failed;
5000     }
5001   
5002   message = _dbus_message_loader_pop_message (loader);
5003   if (message == NULL)
5004     {
5005       _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n");
5006       goto failed;
5007     }
5008   
5009   if (_dbus_string_get_length (&loader->data) > 0)
5010     {
5011       _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n");
5012       goto failed;
5013     }
5014
5015   /* Verify that we're able to properly deal with the message.
5016    * For example, this would detect improper handling of messages
5017    * in nonstandard byte order.
5018    */
5019   if (!check_message_handling (message))
5020     goto failed;  
5021   
5022   retval = TRUE;
5023
5024  failed:
5025   if (message)
5026     dbus_message_unref (message);
5027
5028   return retval;
5029 }
5030
5031 static dbus_bool_t
5032 check_invalid_message (DBusMessageLoader *loader)
5033 {
5034   dbus_bool_t retval;
5035
5036   retval = FALSE;
5037
5038   if (!_dbus_message_loader_queue_messages (loader))
5039     _dbus_assert_not_reached ("no memory to queue messages");
5040   
5041   if (!_dbus_message_loader_get_is_corrupted (loader))
5042     {
5043       _dbus_warn ("loader not corrupted on message that was expected to be invalid\n");
5044       goto failed;
5045     }
5046
5047   retval = TRUE;
5048
5049  failed:
5050   return retval;
5051 }
5052
5053 static dbus_bool_t
5054 check_incomplete_message (DBusMessageLoader *loader)
5055 {
5056   DBusMessage *message;
5057   dbus_bool_t retval;
5058
5059   message = NULL;
5060   retval = FALSE;
5061
5062   if (!_dbus_message_loader_queue_messages (loader))
5063     _dbus_assert_not_reached ("no memory to queue messages");
5064   
5065   if (_dbus_message_loader_get_is_corrupted (loader))
5066     {
5067       _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n");
5068       goto failed;
5069     }
5070   
5071   message = _dbus_message_loader_pop_message (loader);
5072   if (message != NULL)
5073     {
5074       _dbus_warn ("loaded message that was expected to be incomplete\n");
5075       goto failed;
5076     }
5077
5078   retval = TRUE;
5079
5080  failed:
5081   if (message)
5082     dbus_message_unref (message);
5083   return retval;
5084 }
5085
5086 static dbus_bool_t
5087 check_loader_results (DBusMessageLoader      *loader,
5088                       DBusMessageValidity     validity)
5089 {
5090   if (!_dbus_message_loader_queue_messages (loader))
5091     _dbus_assert_not_reached ("no memory to queue messages");
5092   
5093   switch (validity)
5094     {
5095     case _DBUS_MESSAGE_VALID:
5096       return check_have_valid_message (loader);
5097     case _DBUS_MESSAGE_INVALID:
5098       return check_invalid_message (loader);
5099     case _DBUS_MESSAGE_INCOMPLETE:
5100       return check_incomplete_message (loader);
5101     case _DBUS_MESSAGE_UNKNOWN:
5102       return TRUE;
5103     }
5104
5105   _dbus_assert_not_reached ("bad DBusMessageValidity");
5106   return FALSE;
5107 }
5108
5109
5110 /**
5111  * Loads the message in the given message file.
5112  *
5113  * @param filename filename to load
5114  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
5115  * @param data string to load message into
5116  * @returns #TRUE if the message was loaded
5117  */
5118 dbus_bool_t
5119 dbus_internal_do_not_use_load_message_file (const DBusString    *filename,
5120                                             dbus_bool_t          is_raw,
5121                                             DBusString          *data)
5122 {
5123   dbus_bool_t retval;
5124
5125   retval = FALSE;  
5126
5127   if (is_raw)
5128     {
5129       DBusError error;
5130
5131       _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename));
5132       dbus_error_init (&error);
5133       if (!_dbus_file_get_contents (data, filename, &error))
5134         {
5135           _dbus_warn ("Could not load message file %s: %s\n",
5136                       _dbus_string_get_const_data (filename),
5137                       error.message);
5138           dbus_error_free (&error);
5139           goto failed;
5140         }
5141     }
5142   else
5143     {
5144       if (!_dbus_message_data_load (data, filename))
5145         {
5146           _dbus_warn ("Could not load message file %s\n",
5147                       _dbus_string_get_const_data (filename));
5148           goto failed;
5149         }
5150     }
5151
5152   retval = TRUE;
5153   
5154  failed:
5155
5156   return retval;
5157 }
5158
5159 /**
5160  * Tries loading the message in the given message file
5161  * and verifies that DBusMessageLoader can handle it.
5162  *
5163  * @param filename filename to load
5164  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
5165  * @param expected_validity what the message has to be like to return #TRUE
5166  * @returns #TRUE if the message has the expected validity
5167  */
5168 dbus_bool_t
5169 dbus_internal_do_not_use_try_message_file (const DBusString    *filename,
5170                                            dbus_bool_t          is_raw,
5171                                            DBusMessageValidity  expected_validity)
5172 {
5173   DBusString data;
5174   dbus_bool_t retval;
5175
5176   retval = FALSE;
5177   
5178   if (!_dbus_string_init (&data))
5179     _dbus_assert_not_reached ("could not allocate string\n");
5180
5181   if (!dbus_internal_do_not_use_load_message_file (filename, is_raw,
5182                                                    &data))
5183     goto failed;
5184
5185   retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity);
5186
5187  failed:
5188
5189   if (!retval)
5190     {
5191       if (_dbus_string_get_length (&data) > 0)
5192         _dbus_verbose_bytes_of_string (&data, 0,
5193                                        _dbus_string_get_length (&data));
5194       
5195       _dbus_warn ("Failed message loader test on %s\n",
5196                   _dbus_string_get_const_data (filename));
5197     }
5198   
5199   _dbus_string_free (&data);
5200
5201   return retval;
5202 }
5203
5204 /**
5205  * Tries loading the given message data.
5206  *
5207  *
5208  * @param data the message data
5209  * @param expected_validity what the message has to be like to return #TRUE
5210  * @returns #TRUE if the message has the expected validity
5211  */
5212 dbus_bool_t
5213 dbus_internal_do_not_use_try_message_data (const DBusString    *data,
5214                                            DBusMessageValidity  expected_validity)
5215 {
5216   DBusMessageLoader *loader;
5217   dbus_bool_t retval;
5218   int len;
5219   int i;
5220
5221   loader = NULL;
5222   retval = FALSE;
5223
5224   /* Write the data one byte at a time */
5225   
5226   loader = _dbus_message_loader_new ();
5227
5228   /* check some trivial loader functions */
5229   _dbus_message_loader_ref (loader);
5230   _dbus_message_loader_unref (loader);
5231   _dbus_message_loader_get_max_message_size (loader);
5232   
5233   len = _dbus_string_get_length (data);
5234   for (i = 0; i < len; i++)
5235     {
5236       DBusString *buffer;
5237
5238       _dbus_message_loader_get_buffer (loader, &buffer);
5239       _dbus_string_append_byte (buffer,
5240                                 _dbus_string_get_byte (data, i));
5241       _dbus_message_loader_return_buffer (loader, buffer, 1);
5242     }
5243   
5244   if (!check_loader_results (loader, expected_validity))
5245     goto failed;
5246
5247   _dbus_message_loader_unref (loader);
5248   loader = NULL;
5249
5250   /* Write the data all at once */
5251   
5252   loader = _dbus_message_loader_new ();
5253
5254   {
5255     DBusString *buffer;
5256     
5257     _dbus_message_loader_get_buffer (loader, &buffer);
5258     _dbus_string_copy (data, 0, buffer,
5259                        _dbus_string_get_length (buffer));
5260     _dbus_message_loader_return_buffer (loader, buffer, 1);
5261   }
5262   
5263   if (!check_loader_results (loader, expected_validity))
5264     goto failed;
5265
5266   _dbus_message_loader_unref (loader);
5267   loader = NULL;  
5268
5269   /* Write the data 2 bytes at a time */
5270   
5271   loader = _dbus_message_loader_new ();
5272
5273   len = _dbus_string_get_length (data);
5274   for (i = 0; i < len; i += 2)
5275     {
5276       DBusString *buffer;
5277
5278       _dbus_message_loader_get_buffer (loader, &buffer);
5279       _dbus_string_append_byte (buffer,
5280                                 _dbus_string_get_byte (data, i));
5281       if ((i+1) < len)
5282         _dbus_string_append_byte (buffer,
5283                                   _dbus_string_get_byte (data, i+1));
5284       _dbus_message_loader_return_buffer (loader, buffer, 1);
5285     }
5286   
5287   if (!check_loader_results (loader, expected_validity))
5288     goto failed;
5289
5290   _dbus_message_loader_unref (loader);
5291   loader = NULL;
5292   
5293   retval = TRUE;
5294   
5295  failed:
5296   
5297   if (loader)
5298     _dbus_message_loader_unref (loader);
5299   
5300   return retval;
5301 }
5302
5303 static dbus_bool_t
5304 process_test_subdir (const DBusString          *test_base_dir,
5305                      const char                *subdir,
5306                      DBusMessageValidity        validity,
5307                      DBusForeachMessageFileFunc function,
5308                      void                      *user_data)
5309 {
5310   DBusString test_directory;
5311   DBusString filename;
5312   DBusDirIter *dir;
5313   dbus_bool_t retval;
5314   DBusError error;
5315
5316   retval = FALSE;
5317   dir = NULL;
5318   
5319   if (!_dbus_string_init (&test_directory))
5320     _dbus_assert_not_reached ("didn't allocate test_directory\n");
5321
5322   _dbus_string_init_const (&filename, subdir);
5323   
5324   if (!_dbus_string_copy (test_base_dir, 0,
5325                           &test_directory, 0))
5326     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
5327   
5328   if (!_dbus_concat_dir_and_file (&test_directory, &filename))    
5329     _dbus_assert_not_reached ("couldn't allocate full path");
5330
5331   _dbus_string_free (&filename);
5332   if (!_dbus_string_init (&filename))
5333     _dbus_assert_not_reached ("didn't allocate filename string\n");
5334
5335   dbus_error_init (&error);
5336   dir = _dbus_directory_open (&test_directory, &error);
5337   if (dir == NULL)
5338     {
5339       _dbus_warn ("Could not open %s: %s\n",
5340                   _dbus_string_get_const_data (&test_directory),
5341                   error.message);
5342       dbus_error_free (&error);
5343       goto failed;
5344     }
5345
5346   printf ("Testing:\n");
5347   
5348  next:
5349   while (_dbus_directory_get_next_file (dir, &filename, &error))
5350     {
5351       DBusString full_path;
5352       dbus_bool_t is_raw;
5353       
5354       if (!_dbus_string_init (&full_path))
5355         _dbus_assert_not_reached ("couldn't init string");
5356
5357       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
5358         _dbus_assert_not_reached ("couldn't copy dir to full_path");
5359
5360       if (!_dbus_concat_dir_and_file (&full_path, &filename))
5361         _dbus_assert_not_reached ("couldn't concat file to dir");
5362
5363       if (_dbus_string_ends_with_c_str (&filename, ".message"))
5364         is_raw = FALSE;
5365       else if (_dbus_string_ends_with_c_str (&filename, ".message-raw"))
5366         is_raw = TRUE;
5367       else
5368         {
5369           _dbus_verbose ("Skipping non-.message file %s\n",
5370                          _dbus_string_get_const_data (&filename));
5371           _dbus_string_free (&full_path);
5372           goto next;
5373         }
5374
5375       printf ("    %s\n",
5376               _dbus_string_get_const_data (&filename));
5377       
5378       _dbus_verbose (" expecting %s\n",
5379                      validity == _DBUS_MESSAGE_VALID ? "valid" :
5380                      (validity == _DBUS_MESSAGE_INVALID ? "invalid" :
5381                       (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")));
5382       
5383       if (! (*function) (&full_path, is_raw, validity, user_data))
5384         {
5385           _dbus_string_free (&full_path);
5386           goto failed;
5387         }
5388       else
5389         _dbus_string_free (&full_path);
5390     }
5391
5392   if (dbus_error_is_set (&error))
5393     {
5394       _dbus_warn ("Could not get next file in %s: %s\n",
5395                   _dbus_string_get_const_data (&test_directory),
5396                   error.message);
5397       dbus_error_free (&error);
5398       goto failed;
5399     }
5400     
5401   retval = TRUE;
5402   
5403  failed:
5404
5405   if (dir)
5406     _dbus_directory_close (dir);
5407   _dbus_string_free (&test_directory);
5408   _dbus_string_free (&filename);
5409
5410   return retval;
5411 }
5412                      
5413 /**
5414  * Runs the given function on every message file in the test suite.
5415  * The function should return #FALSE on test failure or fatal error.
5416  *
5417  * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data)
5418  * @param func the function to run
5419  * @param user_data data for function
5420  * @returns #FALSE if there's a failure
5421  */
5422 dbus_bool_t
5423 dbus_internal_do_not_use_foreach_message_file (const char                *test_data_dir,
5424                                                DBusForeachMessageFileFunc func,
5425                                                void                      *user_data)
5426 {
5427   DBusString test_directory;
5428   dbus_bool_t retval;
5429
5430   retval = FALSE;
5431   
5432   _dbus_string_init_const (&test_directory, test_data_dir);
5433
5434   if (!process_test_subdir (&test_directory, "valid-messages",
5435                             _DBUS_MESSAGE_VALID, func, user_data))
5436     goto failed;
5437
5438   if (!process_test_subdir (&test_directory, "invalid-messages",
5439                             _DBUS_MESSAGE_INVALID, func, user_data))
5440     goto failed;
5441   
5442   if (!process_test_subdir (&test_directory, "incomplete-messages",
5443                             _DBUS_MESSAGE_INCOMPLETE, func, user_data))
5444     goto failed;
5445
5446   retval = TRUE;
5447   
5448  failed:
5449
5450   _dbus_string_free (&test_directory);
5451   
5452   return retval;
5453 }
5454
5455 static void
5456 verify_test_message (DBusMessage *message)
5457 {
5458   DBusMessageIter iter, dict;
5459   DBusError error;
5460   dbus_int32_t our_int;
5461   char *our_str;
5462   double our_double;
5463   dbus_bool_t our_bool;
5464   dbus_uint32_t our_uint32;
5465   dbus_int32_t *our_uint32_array;
5466   int our_uint32_array_len;
5467   dbus_int32_t *our_int32_array;
5468   int our_int32_array_len;
5469   char **our_string_array;
5470   int our_string_array_len;
5471 #ifdef DBUS_HAVE_INT64
5472   dbus_int64_t our_int64;
5473   dbus_uint64_t our_uint64;
5474   dbus_int64_t *our_uint64_array;
5475   int our_uint64_array_len;
5476   dbus_int64_t *our_int64_array;
5477   int our_int64_array_len;
5478 #endif
5479   double *our_double_array;
5480   int our_double_array_len;
5481   unsigned char *our_byte_array;
5482   int our_byte_array_len;
5483   unsigned char *our_boolean_array;
5484   int our_boolean_array_len;
5485   
5486   dbus_message_iter_init (message, &iter);
5487
5488   dbus_error_init (&error);
5489   if (!dbus_message_iter_get_args (&iter, &error,
5490                                    DBUS_TYPE_INT32, &our_int,
5491 #ifdef DBUS_HAVE_INT64
5492                                    DBUS_TYPE_INT64, &our_int64,
5493                                    DBUS_TYPE_UINT64, &our_uint64,
5494 #endif
5495                                    DBUS_TYPE_STRING, &our_str,
5496                                    DBUS_TYPE_DOUBLE, &our_double,
5497                                    DBUS_TYPE_BOOLEAN, &our_bool,
5498                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
5499                                    &our_uint32_array, &our_uint32_array_len,
5500                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
5501                                    &our_int32_array, &our_int32_array_len,
5502 #ifdef DBUS_HAVE_INT64
5503                                    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64,
5504                                    &our_uint64_array, &our_uint64_array_len,
5505                                    DBUS_TYPE_ARRAY, DBUS_TYPE_INT64,
5506                                    &our_int64_array, &our_int64_array_len,
5507 #endif
5508                                    DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
5509                                    &our_string_array, &our_string_array_len,
5510                                    DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE,
5511                                    &our_double_array, &our_double_array_len,
5512                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
5513                                    &our_byte_array, &our_byte_array_len,
5514                                    DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN,
5515                                    &our_boolean_array, &our_boolean_array_len,
5516                                    0))
5517     {
5518       _dbus_warn ("error: %s - %s\n", error.name,
5519                   (error.message != NULL) ? error.message : "no message");
5520       _dbus_assert_not_reached ("Could not get arguments");
5521     }
5522
5523   if (our_int != -0x12345678)
5524     _dbus_assert_not_reached ("integers differ!");
5525
5526 #ifdef DBUS_HAVE_INT64
5527   if (our_int64 != -0x123456789abcd)
5528     _dbus_assert_not_reached ("64-bit integers differ!");
5529   if (our_uint64 != 0x123456789abcd)
5530     _dbus_assert_not_reached ("64-bit unsigned integers differ!");
5531 #endif
5532   
5533   if (our_double != 3.14159)
5534     _dbus_assert_not_reached ("doubles differ!");
5535
5536   if (strcmp (our_str, "Test string") != 0)
5537     _dbus_assert_not_reached ("strings differ!");
5538   dbus_free (our_str);
5539
5540   if (!our_bool)
5541     _dbus_assert_not_reached ("booleans differ");
5542
5543   if (our_uint32_array_len != 4 ||
5544       our_uint32_array[0] != 0x12345678 ||
5545       our_uint32_array[1] != 0x23456781 ||
5546       our_uint32_array[2] != 0x34567812 ||
5547       our_uint32_array[3] != 0x45678123)
5548     _dbus_assert_not_reached ("uint array differs");
5549   dbus_free (our_uint32_array);
5550
5551   if (our_int32_array_len != 4 ||
5552       our_int32_array[0] != 0x12345678 ||
5553       our_int32_array[1] != -0x23456781 ||
5554       our_int32_array[2] != 0x34567812 ||
5555       our_int32_array[3] != -0x45678123)
5556     _dbus_assert_not_reached ("int array differs");
5557   dbus_free (our_int32_array);
5558
5559 #ifdef DBUS_HAVE_INT64
5560   if (our_uint64_array_len != 4 ||
5561       our_uint64_array[0] != 0x12345678 ||
5562       our_uint64_array[1] != 0x23456781 ||
5563       our_uint64_array[2] != 0x34567812 ||
5564       our_uint64_array[3] != 0x45678123)
5565     _dbus_assert_not_reached ("uint64 array differs");
5566   dbus_free (our_uint64_array);
5567   
5568   if (our_int64_array_len != 4 ||
5569       our_int64_array[0] != 0x12345678 ||
5570       our_int64_array[1] != -0x23456781 ||
5571       our_int64_array[2] != 0x34567812 ||
5572       our_int64_array[3] != -0x45678123)
5573     _dbus_assert_not_reached ("int64 array differs");
5574   dbus_free (our_int64_array);
5575 #endif /* DBUS_HAVE_INT64 */
5576   
5577   if (our_string_array_len != 4)
5578     _dbus_assert_not_reached ("string array has wrong length");
5579
5580   if (strcmp (our_string_array[0], "Foo") != 0 ||
5581       strcmp (our_string_array[1], "bar") != 0 ||
5582       strcmp (our_string_array[2], "") != 0 ||
5583       strcmp (our_string_array[3], "woo woo woo woo") != 0)
5584     _dbus_assert_not_reached ("string array differs");
5585
5586   dbus_free_string_array (our_string_array);
5587
5588   if (our_double_array_len != 3)
5589     _dbus_assert_not_reached ("double array had wrong length");
5590
5591   /* On all IEEE machines (i.e. everything sane) exact equality
5592    * should be preserved over the wire
5593    */
5594   if (our_double_array[0] != 0.1234 ||
5595       our_double_array[1] != 9876.54321 ||
5596       our_double_array[2] != -300.0)
5597     _dbus_assert_not_reached ("double array had wrong values");
5598
5599   dbus_free (our_double_array);
5600
5601   if (our_byte_array_len != 4)
5602     _dbus_assert_not_reached ("byte array had wrong length");
5603
5604   if (our_byte_array[0] != 'a' ||
5605       our_byte_array[1] != 'b' ||
5606       our_byte_array[2] != 'c' ||
5607       our_byte_array[3] != 234)
5608     _dbus_assert_not_reached ("byte array had wrong values");
5609
5610   dbus_free (our_byte_array);
5611
5612   if (our_boolean_array_len != 5)
5613     _dbus_assert_not_reached ("bool array had wrong length");
5614
5615   if (our_boolean_array[0] != TRUE ||
5616       our_boolean_array[1] != FALSE ||
5617       our_boolean_array[2] != TRUE ||
5618       our_boolean_array[3] != TRUE ||
5619       our_boolean_array[4] != FALSE)
5620     _dbus_assert_not_reached ("bool array had wrong values");
5621
5622   dbus_free (our_boolean_array);
5623   
5624   if (!dbus_message_iter_next (&iter))
5625     _dbus_assert_not_reached ("Reached end of arguments");
5626
5627   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_DICT)
5628     _dbus_assert_not_reached ("not dict type");
5629      
5630   if (!dbus_message_iter_init_dict_iterator (&iter, &dict))
5631     _dbus_assert_not_reached ("dict iter failed");
5632
5633   our_str = dbus_message_iter_get_dict_key (&dict);
5634   if (our_str == NULL || strcmp (our_str, "test") != 0)
5635     _dbus_assert_not_reached ("wrong dict key");
5636   dbus_free (our_str);
5637
5638   if (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_UINT32)
5639     {
5640       _dbus_verbose ("dict entry type: %d\n", dbus_message_iter_get_arg_type (&dict));
5641       _dbus_assert_not_reached ("wrong dict entry type");
5642     }
5643
5644   if ((our_uint32 = dbus_message_iter_get_uint32 (&dict)) != 0xDEADBEEF)
5645     {
5646       _dbus_verbose ("dict entry val: %x\n", our_uint32);
5647       _dbus_assert_not_reached ("wrong dict entry value");
5648     }
5649
5650   if (dbus_message_iter_next (&dict))
5651     _dbus_assert_not_reached ("Didn't reach end of dict");
5652   
5653   if (!dbus_message_iter_next (&iter))
5654     _dbus_assert_not_reached ("Reached end of arguments");
5655   
5656   if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32)
5657     _dbus_assert_not_reached ("wrong type after dict");
5658   
5659   if (dbus_message_iter_get_uint32 (&iter) != 0xCAFEBABE)
5660     _dbus_assert_not_reached ("wrong value after dict");
5661
5662   if (dbus_message_iter_next (&iter))
5663     _dbus_assert_not_reached ("Didn't reach end of arguments");
5664 }
5665
5666 /**
5667  * @ingroup DBusMessageInternals
5668  * Unit test for DBusMessage.
5669  *
5670  * @returns #TRUE on success.
5671  */
5672 dbus_bool_t
5673 _dbus_message_test (const char *test_data_dir)
5674 {
5675   DBusMessage *message;
5676   DBusMessageLoader *loader;
5677   DBusMessageIter iter, child_iter, child_iter2, child_iter3;
5678   int i;
5679   const char *data;
5680   DBusMessage *copy;
5681   const char *name1;
5682   const char *name2;
5683   const dbus_uint32_t our_uint32_array[] =
5684     { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
5685   const dbus_uint32_t our_int32_array[] =
5686     { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
5687 #ifdef DBUS_HAVE_INT64
5688   const dbus_uint64_t our_uint64_array[] =
5689     { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
5690   const dbus_uint64_t our_int64_array[] =
5691     { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
5692 #endif
5693   const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" };
5694   const double our_double_array[] = { 0.1234, 9876.54321, -300.0 };
5695   const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 };
5696   const unsigned char our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE };
5697   
5698   _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
5699
5700   message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test");
5701   _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test"));
5702   _dbus_message_set_serial (message, 1234);
5703   dbus_message_set_sender (message, "org.foo.bar");
5704   _dbus_assert (dbus_message_has_sender (message, "org.foo.bar"));
5705   dbus_message_set_sender (message, NULL);
5706   _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar"));
5707   _dbus_assert (dbus_message_get_serial (message) == 1234);
5708   _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test"));
5709
5710   _dbus_assert (dbus_message_get_is_error (message) == FALSE);
5711   dbus_message_set_is_error (message, TRUE);
5712   _dbus_assert (dbus_message_get_is_error (message) == TRUE);
5713   dbus_message_set_is_error (message, FALSE);
5714   _dbus_assert (dbus_message_get_is_error (message) == FALSE);
5715   
5716   dbus_message_unref (message);
5717   
5718   /* Test the vararg functions */
5719   message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test");
5720   _dbus_message_set_serial (message, 1);
5721   dbus_message_append_args (message,
5722                             DBUS_TYPE_INT32, -0x12345678,
5723 #ifdef DBUS_HAVE_INT64
5724                             DBUS_TYPE_INT64, -0x123456789abcd,
5725                             DBUS_TYPE_UINT64, 0x123456789abcd,
5726 #endif
5727                             DBUS_TYPE_STRING, "Test string",
5728                             DBUS_TYPE_DOUBLE, 3.14159,
5729                             DBUS_TYPE_BOOLEAN, TRUE,
5730                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, our_uint32_array,
5731                             _DBUS_N_ELEMENTS (our_uint32_array),
5732                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, our_int32_array,
5733                             _DBUS_N_ELEMENTS (our_int32_array),
5734                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, our_uint64_array,
5735                             _DBUS_N_ELEMENTS (our_uint64_array),
5736                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, our_int64_array,
5737                             _DBUS_N_ELEMENTS (our_int64_array),
5738                             DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, our_string_array,
5739                             _DBUS_N_ELEMENTS (our_string_array),
5740                             DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, our_double_array,
5741                             _DBUS_N_ELEMENTS (our_double_array),
5742                             DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, our_byte_array,
5743                             _DBUS_N_ELEMENTS (our_byte_array),
5744                             DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, our_boolean_array,
5745                             _DBUS_N_ELEMENTS (our_boolean_array),
5746                             0);
5747   
5748   dbus_message_append_iter_init (message, &iter);
5749   dbus_message_iter_append_dict (&iter, &child_iter);
5750   dbus_message_iter_append_dict_key (&child_iter, "test");
5751   dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF);
5752   dbus_message_iter_append_uint32 (&iter, 0xCAFEBABE);
5753   
5754   _dbus_verbose_bytes_of_string (&message->header, 0,
5755                                  _dbus_string_get_length (&message->header));
5756   _dbus_verbose_bytes_of_string (&message->body, 0,
5757                                  _dbus_string_get_length (&message->body));
5758
5759   verify_test_message (message);
5760
5761   copy = dbus_message_copy (message);
5762   
5763   _dbus_assert (message->client_serial == copy->client_serial);
5764   _dbus_assert (message->reply_serial == copy->reply_serial);
5765   _dbus_assert (message->header_padding == copy->header_padding);
5766   
5767   _dbus_assert (_dbus_string_get_length (&message->header) ==
5768                 _dbus_string_get_length (&copy->header));
5769
5770   _dbus_assert (_dbus_string_get_length (&message->body) ==
5771                 _dbus_string_get_length (&copy->body));
5772
5773   verify_test_message (copy);
5774
5775   name1 = dbus_message_get_name (message);
5776   name2 = dbus_message_get_name (copy);
5777
5778   _dbus_assert (strcmp (name1, name2) == 0);
5779   
5780   dbus_message_unref (message);
5781   dbus_message_unref (copy);
5782   
5783   message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test");
5784   _dbus_message_set_serial (message, 1);
5785   dbus_message_set_reply_serial (message, 0x12345678);
5786
5787   dbus_message_append_iter_init (message, &iter);
5788   dbus_message_iter_append_string (&iter, "Test string");
5789   dbus_message_iter_append_int32 (&iter, -0x12345678);
5790   dbus_message_iter_append_uint32 (&iter, 0xedd1e);
5791   dbus_message_iter_append_double (&iter, 3.14159);
5792
5793   dbus_message_iter_append_array (&iter, &child_iter, DBUS_TYPE_DOUBLE);
5794   dbus_message_iter_append_double (&child_iter, 1.5);
5795   dbus_message_iter_append_double (&child_iter, 2.5);
5796
5797   /* dict */
5798   dbus_message_iter_append_dict (&iter, &child_iter);
5799   dbus_message_iter_append_dict_key (&child_iter, "test");
5800   dbus_message_iter_append_uint32 (&child_iter, 0xDEADBEEF);
5801
5802   /* array of array of int32  (in dict) */
5803   dbus_message_iter_append_dict_key (&child_iter, "array");
5804   dbus_message_iter_append_array (&child_iter, &child_iter2, DBUS_TYPE_ARRAY);
5805   dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32);
5806   dbus_message_iter_append_int32 (&child_iter3, 0x12345678);
5807   dbus_message_iter_append_int32 (&child_iter3, 0x23456781);
5808   _dbus_warn ("next call expected to fail with wrong array type\n");
5809   _dbus_assert (!dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_UINT32));
5810   dbus_message_iter_append_array (&child_iter2, &child_iter3, DBUS_TYPE_INT32);
5811   dbus_message_iter_append_int32 (&child_iter3, 0x34567812);
5812   dbus_message_iter_append_int32 (&child_iter3, 0x45678123);
5813   dbus_message_iter_append_int32 (&child_iter3, 0x56781234);
5814   
5815   dbus_message_iter_append_byte (&iter, 0xF0);
5816
5817   dbus_message_iter_append_nil (&iter);
5818
5819   dbus_message_iter_append_named (&iter, "named",
5820                                   "data", 5);
5821   
5822   message_iter_test (message);
5823
5824   /* Message loader test */
5825   _dbus_message_lock (message);
5826   loader = _dbus_message_loader_new ();
5827
5828   /* check ref/unref */
5829   _dbus_message_loader_ref (loader);
5830   _dbus_message_loader_unref (loader);
5831   
5832   /* Write the header data one byte at a time */
5833   data = _dbus_string_get_const_data (&message->header);
5834   for (i = 0; i < _dbus_string_get_length (&message->header); i++)
5835     {
5836       DBusString *buffer;
5837
5838       _dbus_message_loader_get_buffer (loader, &buffer);
5839       _dbus_string_append_byte (buffer, data[i]);
5840       _dbus_message_loader_return_buffer (loader, buffer, 1);
5841     }
5842
5843   /* Write the body data one byte at a time */
5844   data = _dbus_string_get_const_data (&message->body);
5845   for (i = 0; i < _dbus_string_get_length (&message->body); i++)
5846     {
5847       DBusString *buffer;
5848
5849       _dbus_message_loader_get_buffer (loader, &buffer);
5850       _dbus_string_append_byte (buffer, data[i]);
5851       _dbus_message_loader_return_buffer (loader, buffer, 1);
5852     }
5853
5854   dbus_message_unref (message);
5855
5856   /* Now pop back the message */
5857   if (!_dbus_message_loader_queue_messages (loader))
5858     _dbus_assert_not_reached ("no memory to queue messages");
5859   
5860   if (_dbus_message_loader_get_is_corrupted (loader))
5861     _dbus_assert_not_reached ("message loader corrupted");
5862   
5863   message = _dbus_message_loader_pop_message (loader);
5864   if (!message)
5865     _dbus_assert_not_reached ("received a NULL message");
5866
5867   if (dbus_message_get_reply_serial (message) != 0x12345678)
5868     _dbus_assert_not_reached ("reply serial fields differ");
5869   
5870   message_iter_test (message);
5871   
5872   dbus_message_unref (message);
5873   _dbus_message_loader_unref (loader);
5874
5875   /* Now load every message in test_data_dir if we have one */
5876   if (test_data_dir == NULL)
5877     return TRUE;
5878
5879   return dbus_internal_do_not_use_foreach_message_file (test_data_dir,
5880                                                         (DBusForeachMessageFileFunc)
5881                                                         dbus_internal_do_not_use_try_message_file,
5882                                                         NULL);
5883 }
5884
5885 #endif /* DBUS_BUILD_TESTS */