2005-01-16 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-marshal-basic.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal-basic.c  Marshalling routines for basic (primitive) types
3  *
4  * Copyright (C) 2002 CodeFactory AB
5  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
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-basic.h"
27
28 #include <string.h>
29
30 /**
31  * @defgroup DBusMarshal marshaling and unmarshaling
32  * @ingroup  DBusInternals
33  * @brief functions to marshal/unmarshal data from the wire
34  *
35  * Types and functions related to converting primitive data types from
36  * wire format to native machine format, and vice versa.
37  *
38  * A signature is just a string with multiple types one after the other.
39  * for example a type is "i" or "(ii)", a signature is "i(ii)"
40  * where i is int and (ii) is struct { int; int; }
41  *
42  * @{
43  */
44
45 static void
46 pack_4_octets (dbus_uint32_t   value,
47                int             byte_order,
48                unsigned char  *data)
49 {
50   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
51
52   if ((byte_order) == DBUS_LITTLE_ENDIAN)
53     *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_LE (value);
54   else
55     *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_BE (value);
56 }
57
58 static void
59 pack_8_octets (DBusBasicValue     value,
60                int                byte_order,
61                unsigned char     *data)
62 {
63   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 8) == data);
64
65 #ifdef DBUS_HAVE_INT64
66   if ((byte_order) == DBUS_LITTLE_ENDIAN)
67     *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_LE (value.u64);
68   else
69     *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_BE (value.u64);
70 #else
71   *(DBus8ByteStruct*)data = value.u64;
72   swap_8_octets ((DBusBasicValue*)data, byte_order);
73 #endif
74 }
75
76 /**
77  * Packs a 32 bit unsigned integer into a data pointer.
78  *
79  * @param value the value
80  * @param byte_order the byte order to use
81  * @param data the data pointer
82  */
83 void
84 _dbus_pack_uint32 (dbus_uint32_t   value,
85                    int             byte_order,
86                    unsigned char  *data)
87 {
88   pack_4_octets (value, byte_order, data);
89 }
90
91 /**
92  * Packs a 32 bit signed integer into a data pointer.
93  *
94  * @param value the value
95  * @param byte_order the byte order to use
96  * @param data the data pointer
97  */
98 void
99 _dbus_pack_int32 (dbus_int32_t   value,
100                   int            byte_order,
101                   unsigned char *data)
102 {
103   pack_4_octets ((dbus_uint32_t) value, byte_order, data);
104 }
105
106 #ifndef DBUS_HAVE_INT64
107 /* from ORBit */
108 static void
109 swap_bytes (unsigned char *data,
110             unsigned int   len)
111 {
112   unsigned char *p1 = data;
113   unsigned char *p2 = data + len - 1;
114
115   while (p1 < p2)
116     {
117       unsigned char tmp = *p1;
118       *p1 = *p2;
119       *p2 = tmp;
120
121       --p2;
122       ++p1;
123     }
124 }
125 #endif /* !DBUS_HAVE_INT64 */
126
127 static void
128 swap_8_octets (DBusBasicValue    *value,
129                int                byte_order)
130 {
131   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
132     {
133 #ifdef DBUS_HAVE_INT64
134       value->u64 = DBUS_UINT64_SWAP_LE_BE (value->u64);
135 #else
136       swap_bytes ((unsigned char *)value, 8);
137 #endif
138     }
139 }
140
141 #if 0
142 static DBusBasicValue
143 unpack_8_octets (int                  byte_order,
144                  const unsigned char *data)
145 {
146   DBusBasicValue r;
147
148   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 8) == data);
149   _dbus_assert (sizeof (r) == 8);
150
151 #ifdef DBUS_HAVE_INT64
152   if (byte_order == DBUS_LITTLE_ENDIAN)
153     r.u64 = DBUS_UINT64_FROM_LE (*(dbus_uint64_t*)data);
154   else
155     r.u64 = DBUS_UINT64_FROM_BE (*(dbus_uint64_t*)data);
156 #else
157   r.u64 = *(DBus8ByteStruct*)data;
158   swap_8_octets (&r, byte_order);
159 #endif
160
161   return r;
162 }
163 #endif
164
165 #ifndef _dbus_unpack_uint32
166 /**
167  * Unpacks a 32 bit unsigned integer from a data pointer
168  *
169  * @param byte_order The byte order to use
170  * @param data the data pointer
171  * @returns the integer
172  */
173 dbus_uint32_t
174 _dbus_unpack_uint32 (int                  byte_order,
175                      const unsigned char *data)
176 {
177   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
178
179   if (byte_order == DBUS_LITTLE_ENDIAN)
180     return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
181   else
182     return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
183 }
184 #endif /* _dbus_unpack_uint32 */
185
186 /**
187  * Unpacks a 32 bit signed integer from a data pointer
188  *
189  * @param byte_order The byte order to use
190  * @param data the data pointer
191  * @returns the integer
192  */
193 dbus_int32_t
194 _dbus_unpack_int32 (int                  byte_order,
195                     const unsigned char *data)
196 {
197   return (dbus_int32_t) _dbus_unpack_uint32 (byte_order, data);
198 }
199
200 static void
201 set_4_octets (DBusString          *str,
202               int                  offset,
203               dbus_uint32_t        value,
204               int                  byte_order)
205 {
206   char *data;
207
208   _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
209                 byte_order == DBUS_BIG_ENDIAN);
210
211   data = _dbus_string_get_data_len (str, offset, 4);
212
213   _dbus_pack_uint32 (value, byte_order, data);
214 }
215
216 static void
217 set_8_octets (DBusString          *str,
218               int                  offset,
219               DBusBasicValue       value,
220               int                  byte_order)
221 {
222   char *data;
223
224   _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
225                 byte_order == DBUS_BIG_ENDIAN);
226
227   data = _dbus_string_get_data_len (str, offset, 8);
228
229   pack_8_octets (value, byte_order, data);
230 }
231
232 /**
233  * Sets the 4 bytes at the given offset to a marshaled unsigned
234  * integer, replacing anything found there previously.
235  *
236  * @param str the string to write the marshalled int to
237  * @param pos the byte offset where int should be written
238  * @param value the value
239  * @param byte_order the byte order to use
240  *
241  */
242 void
243 _dbus_marshal_set_uint32 (DBusString          *str,
244                           int                  pos,
245                           dbus_uint32_t        value,
246                           int                  byte_order)
247 {
248   set_4_octets (str, pos, value, byte_order);
249 }
250
251 /**
252  * Sets the existing marshaled string at the given offset with
253  * a new marshaled string. The given offset must point to
254  * an existing string or the wrong length will be deleted
255  * and replaced with the new string.
256  *
257  * Note: no attempt is made by this function to re-align
258  * any data which has been already marshalled after this
259  * string. Use with caution.
260  *
261  * @param str the string to write the marshalled string to
262  * @param pos the position of the marshaled string length
263  * @param value the value
264  * @param byte_order the byte order to use
265  * @param old_end_pos place to store byte after the nul byte of the old value
266  * @param new_end_pos place to store byte after the nul byte of the new value
267  * @returns #TRUE on success, #FALSE if no memory
268  *
269  */
270 static dbus_bool_t
271 set_string (DBusString          *str,
272             int                  pos,
273             const char          *value,
274             int                  byte_order,
275             int                 *old_end_pos,
276             int                 *new_end_pos)
277 {
278   int old_len, new_len;
279   DBusString dstr;
280
281   _dbus_string_init_const (&dstr, value);
282
283   _dbus_assert (_DBUS_ALIGN_VALUE (pos, 4) == (unsigned) pos);
284   old_len = _dbus_unpack_uint32 (byte_order,
285                                  _dbus_string_get_const_data_len (str, pos, 4));
286
287   new_len = _dbus_string_get_length (&dstr);
288
289   if (!_dbus_string_replace_len (&dstr, 0, new_len,
290                                  str, pos + 4, old_len))
291     return FALSE;
292
293   _dbus_marshal_set_uint32 (str, pos, new_len, byte_order);
294
295   if (old_end_pos)
296     *old_end_pos = pos + 4 + old_len + 1;
297   if (new_end_pos)
298     *new_end_pos = pos + 4 + new_len + 1;
299
300   return TRUE;
301 }
302
303 /**
304  * Sets the existing marshaled signature at the given offset to a new
305  * marshaled signature. Same basic ideas as set_string().
306  *
307  * @param str the string to write the marshalled signature to
308  * @param pos the position of the marshaled signature length
309  * @param value the value
310  * @param byte_order the byte order to use
311  * @param old_end_pos place to store byte after the nul byte of the old value
312  * @param new_end_pos place to store byte after the nul byte of the new value
313  * @returns #TRUE on success, #FALSE if no memory
314  *
315  */
316 static dbus_bool_t
317 set_signature (DBusString          *str,
318                int                  pos,
319                const char          *value,
320                int                  byte_order,
321                int                 *old_end_pos,
322                int                 *new_end_pos)
323 {
324   int old_len, new_len;
325   DBusString dstr;
326
327   _dbus_string_init_const (&dstr, value);
328
329   old_len = _dbus_string_get_byte (str, pos);
330   new_len = _dbus_string_get_length (&dstr);
331
332   if (!_dbus_string_replace_len (&dstr, 0, new_len,
333                                  str, pos + 1, old_len))
334     return FALSE;
335
336   _dbus_string_set_byte (str, pos, new_len);
337
338   if (old_end_pos)
339     *old_end_pos = pos + 1 + old_len + 1;
340   if (new_end_pos)
341     *new_end_pos = pos + 1 + new_len + 1;
342
343   return TRUE;
344 }
345
346 /**
347  * Sets an existing basic type value to a new value.
348  * Arguments work the same way as _dbus_marshal_basic_type().
349  *
350  * @param str the string
351  * @param pos location of the current value
352  * @param type the type of the current and new values
353  * @param value the address of the new value
354  * @param byte_order byte order for marshaling
355  * @param old_end_pos location to store end position of the old value, or #NULL
356  * @param new_end_pos location to store end position of the new value, or #NULL
357  * @returns #FALSE if no memory
358  */
359 dbus_bool_t
360 _dbus_marshal_set_basic (DBusString       *str,
361                          int               pos,
362                          int               type,
363                          const void       *value,
364                          int               byte_order,
365                          int              *old_end_pos,
366                          int              *new_end_pos)
367 {
368   const DBusBasicValue *vp;
369
370   vp = value;
371
372   switch (type)
373     {
374     case DBUS_TYPE_BYTE:
375     case DBUS_TYPE_BOOLEAN:
376       _dbus_string_set_byte (str, pos, vp->byt);
377       if (old_end_pos)
378         *old_end_pos = pos + 1;
379       if (new_end_pos)
380         *new_end_pos = pos + 1;
381       return TRUE;
382       break;
383     case DBUS_TYPE_INT32:
384     case DBUS_TYPE_UINT32:
385       pos = _DBUS_ALIGN_VALUE (pos, 4);
386       set_4_octets (str, pos, vp->u32, byte_order);
387       if (old_end_pos)
388         *old_end_pos = pos + 4;
389       if (new_end_pos)
390         *new_end_pos = pos + 4;
391       return TRUE;
392       break;
393     case DBUS_TYPE_INT64:
394     case DBUS_TYPE_UINT64:
395     case DBUS_TYPE_DOUBLE:
396       pos = _DBUS_ALIGN_VALUE (pos, 8);
397       set_8_octets (str, pos, *vp, byte_order);
398       if (old_end_pos)
399         *old_end_pos = pos + 8;
400       if (new_end_pos)
401         *new_end_pos = pos + 8;
402       return TRUE;
403       break;
404     case DBUS_TYPE_STRING:
405     case DBUS_TYPE_OBJECT_PATH:
406       pos = _DBUS_ALIGN_VALUE (pos, 4);
407       _dbus_assert (vp->str != NULL);
408       return set_string (str, pos, vp->str, byte_order,
409                          old_end_pos, new_end_pos);
410       break;
411     case DBUS_TYPE_SIGNATURE:
412       _dbus_assert (vp->str != NULL);
413       return set_signature (str, pos, vp->str, byte_order,
414                             old_end_pos, new_end_pos);
415       break;
416     default:
417       _dbus_assert_not_reached ("not a basic type");
418       return FALSE;
419       break;
420     }
421 }
422
423 /**
424  * Convenience function to demarshal a 32 bit unsigned integer.
425  *
426  * @param str the string containing the data
427  * @param byte_order the byte order
428  * @param pos the position in the string
429  * @param new_pos the new position of the string
430  * @returns the demarshaled integer.
431  */
432 dbus_uint32_t
433 _dbus_marshal_read_uint32  (const DBusString *str,
434                             int               pos,
435                             int               byte_order,
436                             int              *new_pos)
437 {
438   pos = _DBUS_ALIGN_VALUE (pos, 4);
439
440   if (new_pos)
441     *new_pos = pos + 4;
442
443   _dbus_assert (pos + 4 <= _dbus_string_get_length (str));
444   
445   return _dbus_unpack_uint32 (byte_order,
446                               _dbus_string_get_const_data (str) + pos);
447 }
448
449 /**
450  * Demarshals a basic-typed value. The "value" pointer is always
451  * the address of a variable of the basic type. So e.g.
452  * if the basic type is "double" then the pointer is
453  * a double*, and if it's "char*" then the pointer is
454  * a "char**".
455  *
456  * A value of type #DBusBasicValue is guaranteed to be large enough to
457  * hold any of the types that may be returned, which is handy if you
458  * are trying to do things generically. For example you can pass
459  * a DBusBasicValue* in to this function, and then pass the same
460  * DBusBasicValue* in to _dbus_marshal_basic_type() in order to
461  * move a value from one place to another.
462  *
463  * @param str the string containing the data
464  * @param pos position in the string
465  * @param type type of value to demarshal
466  * @param value pointer to return value data
467  * @param byte_order the byte order
468  * @param new_pos pointer to update with new position, or #NULL
469  **/
470 void
471 _dbus_marshal_read_basic (const DBusString      *str,
472                           int                    pos,
473                           int                    type,
474                           void                  *value,
475                           int                    byte_order,
476                           int                   *new_pos)
477 {
478   const char *str_data;
479   DBusBasicValue *vp;
480
481   _dbus_assert (_dbus_type_is_basic (type));
482
483   str_data = _dbus_string_get_const_data (str);
484   vp = value;
485
486   switch (type)
487     {
488     case DBUS_TYPE_BYTE:
489     case DBUS_TYPE_BOOLEAN:
490       vp->byt = _dbus_string_get_byte (str, pos);
491       (pos)++;
492       break;
493     case DBUS_TYPE_INT32:
494     case DBUS_TYPE_UINT32:
495       pos = _DBUS_ALIGN_VALUE (pos, 4);
496       vp->u32 = *(dbus_uint32_t *)(str_data + pos);
497       if (byte_order != DBUS_COMPILER_BYTE_ORDER)
498         vp->u32 = DBUS_UINT32_SWAP_LE_BE (vp->u32);
499       pos += 4;
500       break;
501     case DBUS_TYPE_INT64:
502     case DBUS_TYPE_UINT64:
503     case DBUS_TYPE_DOUBLE:
504       pos = _DBUS_ALIGN_VALUE (pos, 8);
505 #ifdef DBUS_HAVE_INT64
506       if (byte_order != DBUS_COMPILER_BYTE_ORDER)
507         vp->u64 = DBUS_UINT64_SWAP_LE_BE (*(dbus_uint64_t*)(str_data + pos));
508       else
509         vp->u64 = *(dbus_uint64_t*)(str_data + pos);
510 #else
511       vp->u64 = *(DBus8ByteStruct*) (str_data + pos);
512       swap_8_octets (vp, byte_order);
513 #endif
514       pos += 8;
515       break;
516     case DBUS_TYPE_STRING:
517     case DBUS_TYPE_OBJECT_PATH:
518       {
519         int len;
520
521         len = _dbus_marshal_read_uint32 (str, pos, byte_order, &pos);
522
523         vp->str = (char*) str_data + pos;
524
525         pos += len + 1; /* length plus nul */
526       }
527       break;
528     case DBUS_TYPE_SIGNATURE:
529       {
530         int len;
531
532         len = _dbus_string_get_byte (str, pos);
533         pos += 1;
534
535         vp->str = (char*) str_data + pos;
536
537         pos += len + 1; /* length plus nul */
538       }
539       break;
540     default:
541       _dbus_warn ("type %s not a basic type\n",
542                   _dbus_type_to_string (type));
543       _dbus_assert_not_reached ("not a basic type");
544       break;
545     }
546
547   if (new_pos)
548     *new_pos = pos;
549 }
550
551 /**
552  * Reads a block of fixed-length basic values, as an optimization
553  * vs. reading each one individually into a new buffer.
554  *
555  * This function returns the data in-place; it does not make a copy,
556  * and it does not swap the bytes.
557  *
558  * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back
559  * and the "value" argument should be a "const double**" and so on.
560  *
561  * @todo we aren't using this function (except in the test suite)
562  * 
563  * @param str the string to read from
564  * @param pos position to read from
565  * @param element_type type of array elements
566  * @param value place to return the array
567  * @param n_elements number of array elements to read
568  * @param byte_order the byte order, used to read the array length
569  * @param new_pos #NULL or location to store a position after the elements
570  */
571 void
572 _dbus_marshal_read_fixed_multi  (const DBusString *str,
573                                  int               pos,
574                                  int               element_type,
575                                  void             *value,
576                                  int               n_elements,
577                                  int               byte_order,
578                                  int              *new_pos)
579 {
580   int array_len;
581   int alignment;
582
583   _dbus_assert (_dbus_type_is_fixed (element_type));
584   _dbus_assert (_dbus_type_is_basic (element_type));
585
586 #if 0
587   _dbus_verbose ("reading %d elements of %s\n",
588                  n_elements, _dbus_type_to_string (element_type));
589 #endif
590   
591   alignment = _dbus_type_get_alignment (element_type);
592
593   pos = _DBUS_ALIGN_VALUE (pos, alignment);
594   
595   array_len = n_elements * alignment;
596
597   *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len);
598   if (new_pos)
599     *new_pos = pos + array_len;
600 }
601
602 static dbus_bool_t
603 marshal_4_octets (DBusString   *str,
604                   int           insert_at,
605                   dbus_uint32_t value,
606                   int           byte_order,
607                   int          *pos_after)
608 {
609   dbus_bool_t retval;
610   int orig_len;
611
612   _dbus_assert (sizeof (value) == 4);
613
614   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
615     value = DBUS_UINT32_SWAP_LE_BE (value);
616
617   orig_len = _dbus_string_get_length (str);
618
619   retval = _dbus_string_insert_4_aligned (str, insert_at,
620                                           (const unsigned char *)&value);
621
622   if (pos_after)
623     {
624       *pos_after = insert_at + (_dbus_string_get_length (str) - orig_len);
625       _dbus_assert (*pos_after <= _dbus_string_get_length (str));
626     }
627
628   return retval;
629 }
630
631 static dbus_bool_t
632 marshal_8_octets (DBusString    *str,
633                   int            insert_at,
634                   DBusBasicValue value,
635                   int            byte_order,
636                   int           *pos_after)
637 {
638   dbus_bool_t retval;
639   int orig_len;
640
641   _dbus_assert (sizeof (value) == 8);
642
643   swap_8_octets (&value, byte_order);
644
645   orig_len = _dbus_string_get_length (str);
646
647   retval = _dbus_string_insert_8_aligned (str, insert_at,
648                                           (const unsigned char *)&value);
649
650   if (pos_after)
651     *pos_after = insert_at + _dbus_string_get_length (str) - orig_len;
652
653   return retval;
654 }
655
656 enum
657   {
658     MARSHAL_AS_STRING,
659     MARSHAL_AS_SIGNATURE,
660     MARSHAL_AS_BYTE_ARRAY
661   };
662
663 static dbus_bool_t
664 marshal_len_followed_by_bytes (int                  marshal_as,
665                                DBusString          *str,
666                                int                  insert_at,
667                                const unsigned char *value,
668                                int                  data_len, /* doesn't include nul if any */
669                                int                  byte_order,
670                                int                 *pos_after)
671 {
672   int pos;
673   DBusString value_str;
674   int value_len;
675
676   _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || byte_order == DBUS_BIG_ENDIAN);
677   if (insert_at > _dbus_string_get_length (str))
678     _dbus_warn ("insert_at = %d string len = %d data_len = %d\n",
679                 insert_at, _dbus_string_get_length (str), data_len);
680   
681   if (marshal_as == MARSHAL_AS_BYTE_ARRAY)
682     value_len = data_len;
683   else
684     value_len = data_len + 1; /* value has a nul */
685
686   _dbus_string_init_const_len (&value_str, value, value_len);
687
688   pos = insert_at;
689
690   if (marshal_as == MARSHAL_AS_SIGNATURE)
691     {
692       if (!_dbus_string_insert_byte (str, pos, data_len))
693         goto oom;
694
695       pos += 1;
696     }
697   else
698     {
699       if (!marshal_4_octets (str, pos, data_len,
700                              byte_order, &pos))
701         goto oom;
702     }
703
704   if (!_dbus_string_copy_len (&value_str, 0, value_len,
705                               str, pos))
706     goto oom;
707
708 #if 0
709   /* too expensive */
710   _dbus_assert (_dbus_string_equal_substring (&value_str, 0, value_len,
711                                               str, pos));
712   _dbus_verbose_bytes_of_string (str, pos, value_len);
713 #endif
714
715   pos += value_len;
716
717   if (pos_after)
718     *pos_after = pos;
719
720   return TRUE;
721
722  oom:
723   /* Delete what we've inserted */
724   _dbus_string_delete (str, insert_at, pos - insert_at);
725
726   return FALSE;
727 }
728
729 static dbus_bool_t
730 marshal_string (DBusString    *str,
731                 int            insert_at,
732                 const char    *value,
733                 int            byte_order,
734                 int           *pos_after)
735 {
736   return marshal_len_followed_by_bytes (MARSHAL_AS_STRING,
737                                         str, insert_at, value,
738                                         strlen (value),
739                                         byte_order, pos_after);
740 }
741
742 static dbus_bool_t
743 marshal_signature (DBusString    *str,
744                    int            insert_at,
745                    const char    *value,
746                    int           *pos_after)
747 {
748   return marshal_len_followed_by_bytes (MARSHAL_AS_SIGNATURE,
749                                         str, insert_at, value,
750                                         strlen (value),
751                                         DBUS_COMPILER_BYTE_ORDER, /* irrelevant */
752                                         pos_after);
753 }
754
755 /**
756  * Marshals a basic-typed value. The "value" pointer is always the
757  * address of a variable containing the basic type value.
758  * So for example for int32 it will be dbus_int32_t*, and
759  * for string it will be const char**. This is for symmetry
760  * with _dbus_marshal_read_basic() and to have a simple
761  * consistent rule.
762  *
763  * @param str string to marshal to
764  * @param insert_at where to insert the value
765  * @param type type of value
766  * @param value pointer to a variable containing the value
767  * @param byte_order byte order
768  * @param pos_after #NULL or the position after the type
769  * @returns #TRUE on success
770  **/
771 dbus_bool_t
772 _dbus_marshal_write_basic (DBusString *str,
773                            int         insert_at,
774                            int         type,
775                            const void *value,
776                            int         byte_order,
777                            int        *pos_after)
778 {
779   const DBusBasicValue *vp;
780
781   _dbus_assert (_dbus_type_is_basic (type));
782
783   vp = value;
784
785   switch (type)
786     {
787     case DBUS_TYPE_BYTE:
788     case DBUS_TYPE_BOOLEAN:
789       if (!_dbus_string_insert_byte (str, insert_at, vp->byt))
790         return FALSE;
791       if (pos_after)
792         *pos_after = insert_at + 1;
793       return TRUE;
794       break;
795     case DBUS_TYPE_INT32:
796     case DBUS_TYPE_UINT32:
797       return marshal_4_octets (str, insert_at, vp->u32,
798                                byte_order, pos_after);
799       break;
800     case DBUS_TYPE_INT64:
801     case DBUS_TYPE_UINT64:
802     case DBUS_TYPE_DOUBLE:
803       return marshal_8_octets (str, insert_at, *vp, byte_order, pos_after);
804       break;
805
806     case DBUS_TYPE_STRING:
807     case DBUS_TYPE_OBJECT_PATH:
808       _dbus_assert (vp->str != NULL);
809       return marshal_string (str, insert_at, vp->str, byte_order, pos_after);
810       break;
811     case DBUS_TYPE_SIGNATURE:
812       _dbus_assert (vp->str != NULL);
813       return marshal_signature (str, insert_at, vp->str, pos_after);
814       break;
815     default:
816       _dbus_assert_not_reached ("not a basic type");
817       return FALSE;
818       break;
819     }
820 }
821
822 static dbus_bool_t
823 marshal_1_octets_array (DBusString          *str,
824                         int                  insert_at,
825                         const unsigned char *value,
826                         int                  n_elements,
827                         int                  byte_order,
828                         int                 *pos_after)
829 {
830   int pos;
831   DBusString value_str;
832
833   _dbus_string_init_const_len (&value_str, value, n_elements);
834
835   pos = insert_at;
836
837   if (!_dbus_string_copy_len (&value_str, 0, n_elements,
838                               str, pos))
839     return FALSE;
840
841   pos += n_elements;
842
843   if (pos_after)
844     *pos_after = pos;
845
846   return TRUE;
847 }
848
849 static void
850 swap_array (DBusString *str,
851             int         array_start,
852             int         n_elements,
853             int         byte_order,
854             int         alignment)
855 {
856   _dbus_assert (_DBUS_ALIGN_VALUE (array_start, alignment) == (unsigned) array_start);
857
858   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
859     {
860       unsigned char *d;
861       unsigned char *end;
862
863       /* we use const_data and cast it off so DBusString can be a const string
864        * for the unit tests. don't ask.
865        */
866       d = (unsigned char*) _dbus_string_get_const_data (str) + array_start;
867       end = d + n_elements * alignment;
868
869       if (alignment == 8)
870         {
871           while (d != end)
872             {
873 #ifdef DBUS_HAVE_INT64
874               *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d));
875 #else
876               swap_8_bytes ((DBusBasicValue*) d);
877 #endif
878               d += 8;
879             }
880         }
881       else
882         {
883           _dbus_assert (alignment == 4);
884
885           while (d != end)
886             {
887               *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d));
888               d += 4;
889             }
890         }
891     }
892 }
893
894 static dbus_bool_t
895 marshal_fixed_multi (DBusString           *str,
896                      int                   insert_at,
897                      const DBusBasicValue *value,
898                      int                   n_elements,
899                      int                   byte_order,
900                      int                   alignment,
901                      int                  *pos_after)
902 {
903   int old_string_len;
904   int array_start;
905   DBusString t;
906   int len_in_bytes;
907
908   _dbus_assert (n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / alignment);
909   
910   old_string_len = _dbus_string_get_length (str);
911
912   len_in_bytes = n_elements * alignment;
913   array_start = insert_at;
914   
915   /* Note that we do alignment padding unconditionally
916    * even if the array is empty; this means that
917    * padding + len is always equal to the number of bytes
918    * in the array.
919    */
920
921   if (!_dbus_string_insert_alignment (str, &array_start, alignment))
922     goto error;
923
924   _dbus_string_init_const_len (&t,
925                                (const unsigned char*) value,
926                                len_in_bytes);
927
928   if (!_dbus_string_copy (&t, 0,
929                           str, array_start))
930     goto error;
931
932   swap_array (str, array_start, n_elements, byte_order, alignment);
933
934   if (pos_after)
935     *pos_after = array_start + len_in_bytes;
936   
937   return TRUE;
938
939  error:
940   _dbus_string_delete (str, insert_at,
941                        _dbus_string_get_length (str) - old_string_len);
942
943   return FALSE;
944 }
945
946 /**
947  * Marshals a block of values of fixed-length type all at once, as an
948  * optimization.  _dbus_type_is_fixed() returns #TRUE for fixed-length
949  * types, which are the basic types minus the string-like types.
950  *
951  * The value argument should be the adddress of an
952  * array, so e.g. "const dbus_uint32_t**"
953  *
954  * @param str string to marshal to
955  * @param insert_at where to insert the value
956  * @param element_type type of array elements
957  * @param value address of an array to marshal
958  * @param n_elements number of elements in the array
959  * @param byte_order byte order
960  * @param pos_after #NULL or the position after the type
961  * @returns #TRUE on success
962  **/
963 dbus_bool_t
964 _dbus_marshal_write_fixed_multi (DBusString *str,
965                                  int         insert_at,
966                                  int         element_type,
967                                  const void *value,
968                                  int         n_elements,
969                                  int         byte_order,
970                                  int        *pos_after)
971 {
972   const void* vp = *(const DBusBasicValue**)value;
973   
974   _dbus_assert (_dbus_type_is_fixed (element_type));
975   _dbus_assert (n_elements >= 0);
976
977 #if 0
978   _dbus_verbose ("writing %d elements of %s\n",
979                  n_elements, _dbus_type_to_string (element_type));
980 #endif
981   
982   switch (element_type)
983     {
984     case DBUS_TYPE_BOOLEAN:
985       /* FIXME: we canonicalize to 0 or 1 for the single boolean case
986        * should we here too ? */
987     case DBUS_TYPE_BYTE:
988       return marshal_1_octets_array (str, insert_at, vp, n_elements, byte_order, pos_after);
989       break;
990     case DBUS_TYPE_INT32:
991     case DBUS_TYPE_UINT32:
992       return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 4, pos_after);
993       break;
994     case DBUS_TYPE_INT64:
995     case DBUS_TYPE_UINT64:
996     case DBUS_TYPE_DOUBLE:
997       return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 8, pos_after);
998       break;
999
1000     default:
1001       _dbus_assert_not_reached ("non fixed type in array write");
1002       break;
1003     }
1004
1005   return FALSE;
1006 }
1007
1008
1009 /**
1010  * Skips over a basic-typed value, reporting the following position.
1011  *
1012  * @param str the string containing the data
1013  * @param type type of value to read
1014  * @param byte_order the byte order
1015  * @param pos pointer to position in the string,
1016  *            updated on return to new position
1017  **/
1018 void
1019 _dbus_marshal_skip_basic (const DBusString      *str,
1020                           int                    type,
1021                           int                    byte_order,
1022                           int                   *pos)
1023 {
1024   _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
1025                 byte_order == DBUS_BIG_ENDIAN);
1026   
1027   switch (type)
1028     {
1029     case DBUS_TYPE_BYTE:
1030     case DBUS_TYPE_BOOLEAN:
1031       (*pos)++;
1032       break;
1033     case DBUS_TYPE_INT32:
1034     case DBUS_TYPE_UINT32:
1035       *pos = _DBUS_ALIGN_VALUE (*pos, 4);
1036       *pos += 4;
1037       break;
1038     case DBUS_TYPE_INT64:
1039     case DBUS_TYPE_UINT64:
1040     case DBUS_TYPE_DOUBLE:
1041       *pos = _DBUS_ALIGN_VALUE (*pos, 8);
1042       *pos += 8;
1043       break;
1044     case DBUS_TYPE_STRING:
1045     case DBUS_TYPE_OBJECT_PATH:
1046       {
1047         int len;
1048
1049         len = _dbus_marshal_read_uint32 (str, *pos, byte_order, pos);
1050         
1051         *pos += len + 1; /* length plus nul */
1052       }
1053       break;
1054     case DBUS_TYPE_SIGNATURE:
1055       {
1056         int len;
1057
1058         len = _dbus_string_get_byte (str, *pos);
1059
1060         *pos += len + 2; /* length byte plus length plus nul */
1061       }
1062       break;
1063     default:
1064       _dbus_warn ("type %s not a basic type\n",
1065                   _dbus_type_to_string (type));
1066       _dbus_assert_not_reached ("not a basic type");
1067       break;
1068     }
1069 }
1070
1071 /**
1072  * Skips an array, returning the next position.
1073  *
1074  * @param str the string containing the data
1075  * @param element_type the type of array elements
1076  * @param byte_order the byte order
1077  * @param pos pointer to position in the string,
1078  *            updated on return to new position
1079  */
1080 void
1081 _dbus_marshal_skip_array (const DBusString  *str,
1082                           int                element_type,
1083                           int                byte_order,
1084                           int               *pos)
1085 {
1086   dbus_uint32_t array_len;
1087   int i;
1088   int alignment;
1089
1090   i = _DBUS_ALIGN_VALUE (*pos, 4);
1091
1092   array_len = _dbus_marshal_read_uint32 (str, i, byte_order, &i);
1093
1094   alignment = _dbus_type_get_alignment (element_type);
1095
1096   i = _DBUS_ALIGN_VALUE (i, alignment);
1097
1098   *pos = i + array_len;
1099 }
1100
1101 /**
1102  * Gets the alignment requirement for the given type;
1103  * will be 1, 4, or 8.
1104  *
1105  * @param typecode the type
1106  * @returns alignment of 1, 4, or 8
1107  */
1108 int
1109 _dbus_type_get_alignment (int typecode)
1110 {
1111   switch (typecode)
1112     {
1113     case DBUS_TYPE_BYTE:
1114     case DBUS_TYPE_BOOLEAN:
1115     case DBUS_TYPE_VARIANT:
1116     case DBUS_TYPE_SIGNATURE:
1117       return 1;
1118     case DBUS_TYPE_INT32:
1119     case DBUS_TYPE_UINT32:
1120       /* this stuff is 4 since it starts with a length */
1121     case DBUS_TYPE_STRING:
1122     case DBUS_TYPE_OBJECT_PATH:
1123     case DBUS_TYPE_ARRAY:
1124       return 4;
1125     case DBUS_TYPE_INT64:
1126     case DBUS_TYPE_UINT64:
1127     case DBUS_TYPE_DOUBLE:
1128       /* struct is 8 since it could contain an 8-aligned item
1129        * and it's simpler to just always align structs to 8;
1130        * we want the amount of padding in a struct of a given
1131        * type to be predictable, not location-dependent.
1132        */
1133     case DBUS_TYPE_STRUCT:
1134       return 8;
1135
1136     default:
1137       _dbus_assert_not_reached ("unknown typecode in _dbus_type_get_alignment()");
1138       return 0;
1139     }
1140 }
1141
1142
1143 /**
1144  * Return #TRUE if the typecode is a valid typecode.
1145  * #DBUS_TYPE_INVALID surprisingly enough is not considered valid, and
1146  * random unknown bytes aren't either. This function is safe with
1147  * untrusted data.
1148  *
1149  * @returns #TRUE if valid
1150  */
1151 dbus_bool_t
1152 _dbus_type_is_valid (int typecode)
1153 {
1154   switch (typecode)
1155     {
1156     case DBUS_TYPE_BYTE:
1157     case DBUS_TYPE_BOOLEAN:
1158     case DBUS_TYPE_INT32:
1159     case DBUS_TYPE_UINT32:
1160     case DBUS_TYPE_INT64:
1161     case DBUS_TYPE_UINT64:
1162     case DBUS_TYPE_DOUBLE:
1163     case DBUS_TYPE_STRING:
1164     case DBUS_TYPE_OBJECT_PATH:
1165     case DBUS_TYPE_SIGNATURE:
1166     case DBUS_TYPE_ARRAY:
1167     case DBUS_TYPE_STRUCT:
1168     case DBUS_TYPE_VARIANT:
1169       return TRUE;
1170
1171     default:
1172       return FALSE;
1173     }
1174 }
1175
1176 /** macro that checks whether a typecode is a container type */
1177 #define TYPE_IS_CONTAINER(typecode)             \
1178     ((typecode) == DBUS_TYPE_STRUCT ||          \
1179      (typecode) == DBUS_TYPE_VARIANT ||         \
1180      (typecode) == DBUS_TYPE_ARRAY)
1181
1182 /**
1183  * A "container type" can contain basic types, or nested
1184  * container types. #DBUS_TYPE_INVALID is not a container type.
1185  * This function will crash if passed a typecode that isn't
1186  * in dbus-protocol.h
1187  *
1188  * @returns #TRUE if type is a container
1189  */
1190 dbus_bool_t
1191 _dbus_type_is_container (int typecode)
1192 {
1193   /* only reasonable (non-line-noise) typecodes are allowed */
1194   _dbus_assert (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID);
1195   return TYPE_IS_CONTAINER (typecode);
1196 }
1197
1198 /**
1199  * A "basic type" is a somewhat arbitrary concept, but the intent
1200  * is to include those types that are fully-specified by a single
1201  * typecode, with no additional type information or nested
1202  * values. So all numbers and strings are basic types and
1203  * structs, arrays, and variants are not basic types.
1204  * #DBUS_TYPE_INVALID is not a basic type.
1205  *
1206  * This function is defined to return #TRUE for exactly those
1207  * types that can be written with _dbus_marshal_basic_type()
1208  * and read with _dbus_marshal_read_basic().
1209  *
1210  * This function will crash if passed a typecode that isn't
1211  * in dbus-protocol.h
1212  *
1213  * @returns #TRUE if type is basic
1214  */
1215 dbus_bool_t
1216 _dbus_type_is_basic (int typecode)
1217 {
1218   /* only reasonable (non-line-noise) typecodes are allowed */
1219   _dbus_assert (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID);
1220
1221   /* everything that isn't invalid or a container */
1222   return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode));
1223 }
1224
1225 /**
1226  * Tells you whether values of this type can change length if you set
1227  * them to some other value. For this purpose, you assume that the
1228  * first byte of the old and new value would be in the same location,
1229  * so alignment padding is not a factor.
1230  *
1231  * @returns #FALSE if the type can occupy different lengths
1232  */
1233 dbus_bool_t
1234 _dbus_type_is_fixed (int typecode)
1235 {
1236   switch (typecode)
1237     {
1238     case DBUS_TYPE_BYTE:
1239     case DBUS_TYPE_BOOLEAN:
1240     case DBUS_TYPE_INT32:
1241     case DBUS_TYPE_UINT32:
1242     case DBUS_TYPE_INT64:
1243     case DBUS_TYPE_UINT64:
1244     case DBUS_TYPE_DOUBLE:
1245       return TRUE;
1246     default:
1247       return FALSE;
1248     }
1249 }
1250
1251 /**
1252  * Returns a string describing the given type.
1253  *
1254  * @param typecode the type to describe
1255  * @returns a constant string describing the type
1256  */
1257 const char *
1258 _dbus_type_to_string (int typecode)
1259 {
1260   switch (typecode)
1261     {
1262     case DBUS_TYPE_INVALID:
1263       return "invalid";
1264     case DBUS_TYPE_BOOLEAN:
1265       return "boolean";
1266     case DBUS_TYPE_BYTE:
1267       return "byte";
1268     case DBUS_TYPE_INT32:
1269       return "int32";
1270     case DBUS_TYPE_UINT32:
1271       return "uint32";
1272     case DBUS_TYPE_DOUBLE:
1273       return "double";
1274     case DBUS_TYPE_STRING:
1275       return "string";
1276     case DBUS_TYPE_OBJECT_PATH:
1277       return "object_path";
1278     case DBUS_TYPE_SIGNATURE:
1279       return "signature";
1280     case DBUS_TYPE_STRUCT:
1281       return "struct";
1282     case DBUS_TYPE_ARRAY:
1283       return "array";
1284     case DBUS_TYPE_VARIANT:
1285       return "variant";
1286     case DBUS_STRUCT_BEGIN_CHAR:
1287       return "begin_struct";
1288     case DBUS_STRUCT_END_CHAR:
1289       return "end_struct";
1290     default:
1291       return "unknown";
1292     }
1293 }
1294
1295 /**
1296  * If in verbose mode, print a block of binary data.
1297  *
1298  * @todo right now it prints even if not in verbose mode
1299  *
1300  * @param data the data
1301  * @param len the length of the data
1302  * @param offset where to start counting for byte indexes
1303  */
1304 void
1305 _dbus_verbose_bytes (const unsigned char *data,
1306                      int                  len,
1307                      int                  offset)
1308 {
1309   int i;
1310   const unsigned char *aligned;
1311
1312   _dbus_assert (len >= 0);
1313
1314   /* Print blanks on first row if appropriate */
1315   aligned = _DBUS_ALIGN_ADDRESS (data, 4);
1316   if (aligned > data)
1317     aligned -= 4;
1318   _dbus_assert (aligned <= data);
1319
1320   if (aligned != data)
1321     {
1322       _dbus_verbose ("%4d\t%p: ", - (data - aligned), aligned);
1323       while (aligned != data)
1324         {
1325           _dbus_verbose ("    ");
1326           ++aligned;
1327         }
1328     }
1329
1330   /* now print the bytes */
1331   i = 0;
1332   while (i < len)
1333     {
1334       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
1335         {
1336           _dbus_verbose ("%4d\t%p: ",
1337                          offset + i, &data[i]);
1338         }
1339
1340       if (data[i] >= 32 &&
1341           data[i] <= 126)
1342         _dbus_verbose (" '%c' ", data[i]);
1343       else
1344         _dbus_verbose ("0x%s%x ",
1345                        data[i] <= 0xf ? "0" : "", data[i]);
1346
1347       ++i;
1348
1349       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
1350         {
1351           if (i > 3)
1352             _dbus_verbose ("BE: %d LE: %d",
1353                            _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
1354                            _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
1355
1356           if (i > 7 &&
1357               _DBUS_ALIGN_ADDRESS (&data[i], 8) == &data[i])
1358             {
1359 #ifdef DBUS_HAVE_INT64
1360               /* I think I probably mean "GNU libc printf" and not "GNUC"
1361                * but we'll wait until someone complains. If you hit this,
1362                * just turn off verbose mode as a workaround.
1363                */
1364 #if __GNUC__
1365               _dbus_verbose (" u64: 0x%llx",
1366                              *(dbus_uint64_t*)&data[i-8]);
1367 #endif
1368 #endif
1369               _dbus_verbose (" dbl: %g",
1370                              *(double*)&data[i-8]);
1371             }
1372
1373           _dbus_verbose ("\n");
1374         }
1375     }
1376
1377   _dbus_verbose ("\n");
1378 }
1379
1380 /**
1381  * Dump the given part of the string to verbose log.
1382  *
1383  * @param str the string
1384  * @param start the start of range to dump
1385  * @param len length of range
1386  */
1387 void
1388 _dbus_verbose_bytes_of_string (const DBusString    *str,
1389                                int                  start,
1390                                int                  len)
1391 {
1392   const char *d;
1393   int real_len;
1394
1395   real_len = _dbus_string_get_length (str);
1396
1397   _dbus_assert (start >= 0);
1398
1399   if (start > real_len)
1400     {
1401       _dbus_verbose ("  [%d,%d) is not inside string of length %d\n",
1402                      start, len, real_len);
1403       return;
1404     }
1405
1406   if ((start + len) > real_len)
1407     {
1408       _dbus_verbose ("  [%d,%d) extends outside string of length %d\n",
1409                      start, len, real_len);
1410       len = real_len - start;
1411     }
1412
1413   d = _dbus_string_get_const_data_len (str, start, len);
1414
1415   _dbus_verbose_bytes (d, len, start);
1416 }
1417
1418 /** @} */
1419
1420 #ifdef DBUS_BUILD_TESTS
1421 #include "dbus-test.h"
1422 #include <stdio.h>
1423
1424 static void
1425 swap_test_array (void *array,
1426                  int   len_bytes,
1427                  int   byte_order,
1428                  int   alignment)
1429 {
1430   DBusString t;
1431
1432   if (alignment == 1)
1433     return;
1434   
1435   _dbus_string_init_const_len (&t, array, len_bytes);
1436   swap_array (&t, 0, len_bytes / alignment, byte_order, alignment);
1437 }
1438
1439 #define MARSHAL_BASIC(typename, byte_order, literal)                    \
1440   do {                                                                  \
1441      v_##typename = literal;                                            \
1442      if (!_dbus_marshal_write_basic (&str, pos, DBUS_TYPE_##typename,   \
1443                                     &v_##typename,                      \
1444                                     byte_order, NULL))                  \
1445        _dbus_assert_not_reached ("no memory");                          \
1446    } while (0)
1447
1448 #define DEMARSHAL_BASIC(typename, byte_order)                                   \
1449   do {                                                                          \
1450     _dbus_marshal_read_basic (&str, pos, DBUS_TYPE_##typename, &v_##typename,   \
1451                               byte_order, &pos);                                \
1452   } while (0)
1453
1454 #define DEMARSHAL_BASIC_AND_CHECK(typename, byte_order, literal)                        \
1455   do {                                                                                  \
1456     DEMARSHAL_BASIC (typename, byte_order);                                             \
1457     if (literal != v_##typename)                                                        \
1458       {                                                                                 \
1459         _dbus_verbose_bytes_of_string (&str, dump_pos,                                  \
1460                                      _dbus_string_get_length (&str) - dump_pos);        \
1461         _dbus_assert_not_reached ("demarshaled wrong value");                           \
1462       }                                                                                 \
1463   } while (0)
1464
1465 #define MARSHAL_TEST(typename, byte_order, literal)             \
1466   do {                                                          \
1467     MARSHAL_BASIC (typename, byte_order, literal);              \
1468     dump_pos = pos;                                             \
1469     DEMARSHAL_BASIC_AND_CHECK (typename, byte_order, literal);  \
1470   } while (0)
1471
1472 #define MARSHAL_TEST_STRCMP(typename, byte_order, literal)                              \
1473   do {                                                                                  \
1474     MARSHAL_BASIC (typename, byte_order, literal);                                      \
1475     dump_pos = pos;                                                                     \
1476     DEMARSHAL_BASIC (typename, byte_order);                                             \
1477     if (strcmp (literal, v_##typename) != 0)                                            \
1478       {                                                                                 \
1479         _dbus_verbose_bytes_of_string (&str, dump_pos,                                  \
1480                                        _dbus_string_get_length (&str) - dump_pos);      \
1481         _dbus_warn ("literal '%s'\nvalue  '%s'\n", literal, v_##typename);              \
1482         _dbus_assert_not_reached ("demarshaled wrong value");                           \
1483       }                                                                                 \
1484   } while (0)
1485
1486 #define MARSHAL_FIXED_ARRAY(typename, byte_order, literal)                                      \
1487   do {                                                                                          \
1488      int next;                                                                                  \
1489      v_UINT32 = sizeof(literal);                                                                \
1490      if (!_dbus_marshal_write_basic (&str, pos, DBUS_TYPE_UINT32, &v_UINT32,                    \
1491                                      byte_order, &next))                                        \
1492        _dbus_assert_not_reached ("no memory");                                                  \
1493      v_ARRAY_##typename = literal;                                                              \
1494      if (!_dbus_marshal_write_fixed_multi (&str, next, DBUS_TYPE_##typename,                    \
1495                                            &v_ARRAY_##typename, _DBUS_N_ELEMENTS(literal),      \
1496                                            byte_order, NULL))                                   \
1497        _dbus_assert_not_reached ("no memory");                                                  \
1498    } while (0)
1499
1500 #define DEMARSHAL_FIXED_ARRAY(typename, byte_order)                                             \
1501   do {                                                                                          \
1502     int next;                                                                                   \
1503     alignment = _dbus_type_get_alignment (DBUS_TYPE_##typename);                                \
1504     v_UINT32 = _dbus_marshal_read_uint32 (&str, dump_pos, byte_order, &next);                   \
1505     _dbus_marshal_read_fixed_multi (&str, next, DBUS_TYPE_##typename, &v_ARRAY_##typename,      \
1506                                     v_UINT32/alignment,                                         \
1507                                     byte_order, NULL);                                          \
1508     swap_test_array (v_ARRAY_##typename, v_UINT32,                                              \
1509                      byte_order, alignment);                                                    \
1510   } while (0)
1511
1512 #define DEMARSHAL_FIXED_ARRAY_AND_CHECK(typename, byte_order, literal)                  \
1513   do {                                                                                  \
1514     DEMARSHAL_FIXED_ARRAY (typename, byte_order);                                       \
1515     if (memcmp (literal, v_ARRAY_##typename, sizeof (literal) != 0))                    \
1516       {                                                                                 \
1517         _dbus_verbose ("MARSHALED DATA\n");                                             \
1518         _dbus_verbose_bytes_of_string (&str, dump_pos,                                  \
1519                                       _dbus_string_get_length (&str) - dump_pos);       \
1520         _dbus_verbose ("LITERAL DATA\n");                                               \
1521         _dbus_verbose_bytes ((char*)literal, sizeof (literal), 0);                      \
1522         _dbus_verbose ("READ DATA\n");                                                  \
1523         _dbus_verbose_bytes ((char*)v_ARRAY_##typename, sizeof (literal), 0);           \
1524         _dbus_assert_not_reached ("demarshaled wrong fixed array value");               \
1525       }                                                                                 \
1526   } while (0)
1527
1528 #define MARSHAL_TEST_FIXED_ARRAY(typename, byte_order, literal)         \
1529   do {                                                                  \
1530     MARSHAL_FIXED_ARRAY (typename, byte_order, literal);                \
1531     dump_pos = pos;                                                     \
1532     DEMARSHAL_FIXED_ARRAY_AND_CHECK (typename, byte_order, literal);    \
1533   } while (0)
1534
1535 dbus_bool_t
1536 _dbus_marshal_test (void)
1537 {
1538   int alignment;
1539   DBusString str;
1540   int pos, dump_pos;
1541   unsigned char array1[5] = { 3, 4, 0, 1, 9 };
1542   dbus_int32_t array4[3] = { 123, 456, 789 };
1543 #ifdef DBUS_HAVE_INT64
1544   dbus_int64_t array8[3] = { DBUS_INT64_CONSTANT (0x123ffffffff),
1545                              DBUS_INT64_CONSTANT (0x456ffffffff),
1546                              DBUS_INT64_CONSTANT (0x789ffffffff) };
1547   dbus_int64_t *v_ARRAY_INT64;
1548 #endif
1549   unsigned char *v_ARRAY_BYTE;
1550   dbus_int32_t *v_ARRAY_INT32;
1551   double *v_ARRAY_DOUBLE;
1552   DBusString t;
1553   double v_DOUBLE;
1554   double t_DOUBLE;
1555   dbus_int32_t v_INT32;
1556   dbus_uint32_t v_UINT32;
1557   dbus_int64_t v_INT64;
1558   dbus_uint64_t v_UINT64;
1559   unsigned char v_BYTE;
1560   unsigned char v_BOOLEAN;
1561   const char *v_STRING;
1562   const char *v_SIGNATURE;
1563   const char *v_OBJECT_PATH;
1564   int byte_order;
1565
1566   if (!_dbus_string_init (&str))
1567     _dbus_assert_not_reached ("failed to init string");
1568
1569   pos = 0;
1570
1571   /* Marshal doubles */
1572   MARSHAL_BASIC (DOUBLE, DBUS_BIG_ENDIAN, 3.14);
1573   DEMARSHAL_BASIC (DOUBLE, DBUS_BIG_ENDIAN);
1574   t_DOUBLE = 3.14;
1575   if (!_DBUS_DOUBLES_BITWISE_EQUAL (t_DOUBLE, v_DOUBLE))
1576     _dbus_assert_not_reached ("got wrong double value");
1577
1578   MARSHAL_BASIC (DOUBLE, DBUS_LITTLE_ENDIAN, 3.14);
1579   DEMARSHAL_BASIC (DOUBLE, DBUS_LITTLE_ENDIAN);
1580   t_DOUBLE = 3.14;
1581   if (!_DBUS_DOUBLES_BITWISE_EQUAL (t_DOUBLE, v_DOUBLE))
1582     _dbus_assert_not_reached ("got wrong double value");
1583
1584   /* Marshal signed integers */
1585   MARSHAL_TEST (INT32, DBUS_BIG_ENDIAN, -12345678);
1586   MARSHAL_TEST (INT32, DBUS_LITTLE_ENDIAN, -12345678);
1587
1588   /* Marshal unsigned integers */
1589   MARSHAL_TEST (UINT32, DBUS_BIG_ENDIAN, 0x12345678);
1590   MARSHAL_TEST (UINT32, DBUS_LITTLE_ENDIAN, 0x12345678);
1591
1592 #ifdef DBUS_HAVE_INT64
1593   /* Marshal signed integers */
1594   MARSHAL_TEST (INT64, DBUS_BIG_ENDIAN, DBUS_INT64_CONSTANT (-0x123456789abc7));
1595   MARSHAL_TEST (INT64, DBUS_LITTLE_ENDIAN, DBUS_INT64_CONSTANT (-0x123456789abc7));
1596
1597   /* Marshal unsigned integers */
1598   MARSHAL_TEST (UINT64, DBUS_BIG_ENDIAN, DBUS_UINT64_CONSTANT (0x123456789abc7));
1599   MARSHAL_TEST (UINT64, DBUS_LITTLE_ENDIAN, DBUS_UINT64_CONSTANT (0x123456789abc7));
1600 #endif /* DBUS_HAVE_INT64 */
1601
1602   /* Marshal byte */
1603   MARSHAL_TEST (BYTE, DBUS_BIG_ENDIAN, 5);
1604   MARSHAL_TEST (BYTE, DBUS_LITTLE_ENDIAN, 5);
1605
1606   /* Marshal all possible bools! */
1607   MARSHAL_TEST (BOOLEAN, DBUS_BIG_ENDIAN, FALSE);
1608   MARSHAL_TEST (BOOLEAN, DBUS_LITTLE_ENDIAN, FALSE);
1609   MARSHAL_TEST (BOOLEAN, DBUS_BIG_ENDIAN, TRUE);
1610   MARSHAL_TEST (BOOLEAN, DBUS_LITTLE_ENDIAN, TRUE);
1611
1612   /* Marshal strings */
1613   MARSHAL_TEST_STRCMP (STRING, DBUS_BIG_ENDIAN, "");
1614   MARSHAL_TEST_STRCMP (STRING, DBUS_LITTLE_ENDIAN, "");
1615   MARSHAL_TEST_STRCMP (STRING, DBUS_BIG_ENDIAN, "This is the dbus test string");
1616   MARSHAL_TEST_STRCMP (STRING, DBUS_LITTLE_ENDIAN, "This is the dbus test string");
1617
1618   /* object paths */
1619   MARSHAL_TEST_STRCMP (OBJECT_PATH, DBUS_BIG_ENDIAN, "/a/b/c");
1620   MARSHAL_TEST_STRCMP (OBJECT_PATH, DBUS_LITTLE_ENDIAN, "/a/b/c");
1621
1622   /* signatures */
1623   MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_BIG_ENDIAN, "");
1624   MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, "");
1625   MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_BIG_ENDIAN, "a(ii)");
1626   MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, "a(ii)");
1627
1628   /* Arrays */
1629   MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_BIG_ENDIAN, array4);
1630   MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_LITTLE_ENDIAN, array4);
1631
1632   MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_BIG_ENDIAN, array1);
1633   MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_LITTLE_ENDIAN, array1);
1634   
1635 #ifdef DBUS_HAVE_INT64
1636   MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_BIG_ENDIAN, array8);
1637   MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_LITTLE_ENDIAN, array8);
1638 #endif
1639
1640 #if 0
1641
1642   /*
1643    * FIXME restore the set/pack tests
1644    */
1645
1646 #ifdef DBUS_HAVE_INT64
1647   /* set/pack 64-bit integers */
1648   _dbus_string_set_length (&str, 8);
1649
1650   /* signed little */
1651   _dbus_marshal_set_int64 (&str, DBUS_LITTLE_ENDIAN,
1652                            0, DBUS_INT64_CONSTANT (-0x123456789abc7));
1653
1654   _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) ==
1655                 _dbus_unpack_int64 (DBUS_LITTLE_ENDIAN,
1656                                     _dbus_string_get_const_data (&str)));
1657
1658   /* signed big */
1659   _dbus_marshal_set_int64 (&str, DBUS_BIG_ENDIAN,
1660                            0, DBUS_INT64_CONSTANT (-0x123456789abc7));
1661
1662   _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) ==
1663                 _dbus_unpack_int64 (DBUS_BIG_ENDIAN,
1664                                     _dbus_string_get_const_data (&str)));
1665
1666   /* signed little pack */
1667   _dbus_pack_int64 (DBUS_INT64_CONSTANT (-0x123456789abc7),
1668                     DBUS_LITTLE_ENDIAN,
1669                     _dbus_string_get_data (&str));
1670
1671   _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) ==
1672                 _dbus_unpack_int64 (DBUS_LITTLE_ENDIAN,
1673                                     _dbus_string_get_const_data (&str)));
1674
1675   /* signed big pack */
1676   _dbus_pack_int64 (DBUS_INT64_CONSTANT (-0x123456789abc7),
1677                     DBUS_BIG_ENDIAN,
1678                     _dbus_string_get_data (&str));
1679
1680   _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) ==
1681                 _dbus_unpack_int64 (DBUS_BIG_ENDIAN,
1682                                     _dbus_string_get_const_data (&str)));
1683
1684   /* unsigned little */
1685   _dbus_marshal_set_uint64 (&str, DBUS_LITTLE_ENDIAN,
1686                             0, DBUS_UINT64_CONSTANT (0x123456789abc7));
1687
1688   _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) ==
1689                 _dbus_unpack_uint64 (DBUS_LITTLE_ENDIAN,
1690                                      _dbus_string_get_const_data (&str)));
1691
1692   /* unsigned big */
1693   _dbus_marshal_set_uint64 (&str, DBUS_BIG_ENDIAN,
1694                             0, DBUS_UINT64_CONSTANT (0x123456789abc7));
1695
1696   _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) ==
1697                 _dbus_unpack_uint64 (DBUS_BIG_ENDIAN,
1698                                      _dbus_string_get_const_data (&str)));
1699
1700   /* unsigned little pack */
1701   _dbus_pack_uint64 (DBUS_UINT64_CONSTANT (0x123456789abc7),
1702                      DBUS_LITTLE_ENDIAN,
1703                      _dbus_string_get_data (&str));
1704
1705   _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) ==
1706                 _dbus_unpack_uint64 (DBUS_LITTLE_ENDIAN,
1707                                      _dbus_string_get_const_data (&str)));
1708
1709   /* unsigned big pack */
1710   _dbus_pack_uint64 (DBUS_UINT64_CONSTANT (0x123456789abc7),
1711                      DBUS_BIG_ENDIAN,
1712                      _dbus_string_get_data (&str));
1713
1714   _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) ==
1715                 _dbus_unpack_uint64 (DBUS_BIG_ENDIAN,
1716                                      _dbus_string_get_const_data (&str)));
1717 #endif /* DBUS_HAVE_INT64 */
1718
1719   /* set/pack 32-bit integers */
1720   _dbus_string_set_length (&str, 4);
1721
1722   /* signed little */
1723   _dbus_marshal_set_int32 (&str, DBUS_LITTLE_ENDIAN,
1724                            0, -0x123456);
1725
1726   _dbus_assert (-0x123456 ==
1727                 _dbus_unpack_int32 (DBUS_LITTLE_ENDIAN,
1728                                     _dbus_string_get_const_data (&str)));
1729
1730   /* signed big */
1731   _dbus_marshal_set_int32 (&str, DBUS_BIG_ENDIAN,
1732                            0, -0x123456);
1733
1734   _dbus_assert (-0x123456 ==
1735                 _dbus_unpack_int32 (DBUS_BIG_ENDIAN,
1736                                     _dbus_string_get_const_data (&str)));
1737
1738   /* signed little pack */
1739   _dbus_pack_int32 (-0x123456,
1740                     DBUS_LITTLE_ENDIAN,
1741                     _dbus_string_get_data (&str));
1742
1743   _dbus_assert (-0x123456 ==
1744                 _dbus_unpack_int32 (DBUS_LITTLE_ENDIAN,
1745                                     _dbus_string_get_const_data (&str)));
1746
1747   /* signed big pack */
1748   _dbus_pack_int32 (-0x123456,
1749                     DBUS_BIG_ENDIAN,
1750                     _dbus_string_get_data (&str));
1751
1752   _dbus_assert (-0x123456 ==
1753                 _dbus_unpack_int32 (DBUS_BIG_ENDIAN,
1754                                     _dbus_string_get_const_data (&str)));
1755
1756   /* unsigned little */
1757   _dbus_marshal_set_uint32 (&str,
1758                             0, 0x123456,
1759                             DBUS_LITTLE_ENDIAN);
1760
1761   _dbus_assert (0x123456 ==
1762                 _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN,
1763                                      _dbus_string_get_const_data (&str)));
1764
1765   /* unsigned big */
1766   _dbus_marshal_set_uint32 (&str,
1767                             0, 0x123456,
1768                             DBUS_BIG_ENDIAN);
1769
1770   _dbus_assert (0x123456 ==
1771                 _dbus_unpack_uint32 (DBUS_BIG_ENDIAN,
1772                                      _dbus_string_get_const_data (&str)));
1773
1774   /* unsigned little pack */
1775   _dbus_pack_uint32 (0x123456,
1776                      DBUS_LITTLE_ENDIAN,
1777                      _dbus_string_get_data (&str));
1778
1779   _dbus_assert (0x123456 ==
1780                 _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN,
1781                                      _dbus_string_get_const_data (&str)));
1782
1783   /* unsigned big pack */
1784   _dbus_pack_uint32 (0x123456,
1785                      DBUS_BIG_ENDIAN,
1786                      _dbus_string_get_data (&str));
1787
1788   _dbus_assert (0x123456 ==
1789                 _dbus_unpack_uint32 (DBUS_BIG_ENDIAN,
1790                                      _dbus_string_get_const_data (&str)));
1791
1792 #endif /* set/pack tests for integers */
1793
1794   /* Strings in-place set */
1795   byte_order = DBUS_LITTLE_ENDIAN;
1796   while (TRUE)
1797     {
1798       /* Init a string */
1799       _dbus_string_set_length (&str, 0);
1800
1801       /* reset pos for the macros */
1802       pos = 0;
1803
1804       MARSHAL_TEST_STRCMP (STRING, byte_order, "Hello world");
1805
1806       /* Set it to something longer */
1807       _dbus_string_init_const (&t, "Hello world foo");
1808
1809       v_STRING = _dbus_string_get_const_data (&t);
1810       _dbus_marshal_set_basic (&str, 0, DBUS_TYPE_STRING,
1811                                &v_STRING, byte_order, NULL, NULL);
1812
1813       _dbus_marshal_read_basic (&str, 0, DBUS_TYPE_STRING,
1814                                 &v_STRING, byte_order,
1815                                 NULL);
1816       _dbus_assert (strcmp (v_STRING, "Hello world foo") == 0);
1817
1818       /* Set it to something shorter */
1819       _dbus_string_init_const (&t, "Hello");
1820
1821       v_STRING = _dbus_string_get_const_data (&t);
1822       _dbus_marshal_set_basic (&str, 0, DBUS_TYPE_STRING,
1823                                &v_STRING, byte_order, NULL, NULL);
1824       _dbus_marshal_read_basic (&str, 0, DBUS_TYPE_STRING,
1825                                 &v_STRING, byte_order,
1826                                 NULL);
1827       _dbus_assert (strcmp (v_STRING, "Hello") == 0);
1828
1829       /* Do the other byte order */
1830       if (byte_order == DBUS_LITTLE_ENDIAN)
1831         byte_order = DBUS_BIG_ENDIAN;
1832       else
1833         break;
1834     }
1835
1836   /* Clean up */
1837   _dbus_string_free (&str);
1838
1839   return TRUE;
1840 }
1841
1842 #endif /* DBUS_BUILD_TESTS */