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